Home
avatar

nax

Infinitoai 与 Turnstile:一次浏览器验证机制的技术拆解

这篇文章不讲“怎么一把梭搞定验证”,而是把重点放在机制层:一个真实浏览器里的扩展,为什么能比普通脚本更接近真人环境,它到底利用了哪些浏览器能力。

如果你平时会研究扩展、自动化、反机器人验证或者浏览器事件模型,这篇会比较有意思。

Infinitoai 与 Turnstile:一次浏览器验证机制的技术拆解

Cloudflare Turnstile 已经成了很多网站的人机验证默认选项。它和老式验证码不太一样,很多时候不会直接给你一堆扭曲字符,而是更依赖浏览器环境、事件可信度、行为特征这些信号来做判断。

也正因为这样,很多人第一次研究这类机制时,会很快发现一个现象:

  • 普通脚本很脆
  • 无头环境容易暴露
  • 真实浏览器里的扩展,反而更接近“自然用户环境”

本文就以开源项目 Infinitoai 为切入点,聊聊它背后体现出的几个关键思路。

先看结论:为什么真实浏览器环境更有优势

Infinitoai 的核心价值,并不只是“会点一下复选框”。

更关键的是,它运行在真实 Chrome 浏览器里。

这意味着它天然拥有很多普通脚本拿不到的条件:

  • 更真实的浏览器指纹
  • 更接近自然用户的 API 行为
  • 和页面脚本共享的真实运行环境
  • 可以借助浏览器内部能力来派发输入事件

这件事非常关键。

很多站点的验证逻辑,并不是只盯着“你有没有点击”,而是在看:

  • 这是不是一个可信事件
  • 坐标关系是不是像真人产生的
  • 浏览器环境是不是像真实用户
  • 触发顺序是不是合理

所以研究这类项目时,真正值得看的,不是表面上的“自动点到了”,而是它为什么看起来像真用户。


一、项目结构透露了什么

从项目拆分方式就能看出,它不是一个单点技巧,而是一套分层思路:

  • background.js 负责流程编排
  • 内容脚本负责和页面交互
  • 专门的补丁脚本在页面很早阶段注入
  • 侧边栏承担控制面板职能

这种结构说明了一件事:

它不是靠一个暴力脚本硬点,而是把“环境修补、页面感知、事件派发、结果判断”拆成了几层。

这也是比较成熟的浏览器自动化项目常见的设计方式。


二、为什么要在页面早期修补事件坐标

Turnstile 这类验证,会观察鼠标事件的一些属性。

比如:

  • clientX
  • clientY
  • screenX
  • screenY

真实用户点击时,这些值之间通常有合理关系。

而如果是程序构造的合成事件,很多时候就会出现很奇怪的特征,比如:

  • screenXscreenY 接近 0
  • 坐标之间关系不自然
  • 每次都机械一致

所以项目里一个很关键的思路,是在页面脚本执行之前尽早注入补丁,对坐标相关属性做修正,让事件在表面上更接近真实浏览器产生的样子。

这里有三个很重要的注入条件

{
  "run_at": "document_start",
  "world": "MAIN",
  "all_frames": true
}

这三个点几乎缺一不可:

  • document_start:越早越好,必须赶在页面主要逻辑运行前。
  • MAIN:要进入页面主世界,而不是只活在扩展自己的隔离环境里。
  • all_frames:验证组件常常在 iframe 里,不进 frame 基本等于白搭。

这组配置本身,就已经很能说明浏览器验证对“上下文位置”有多敏感了。


三、为什么“可信事件”比普通点击更重要

普通前端里常见的触发方式,比如:

  • element.click()
  • dispatchEvent(new MouseEvent(...))

在很多业务场景里已经够用了。

但放到反机器人验证里,这种方式经常不够。

原因很简单:页面不仅在看你有没有发出一个点击,还在看这个点击是否足够“可信”。

有些事件虽然能把前端 UI 点亮,却仍然会留下很重的自动化痕迹。

而 Infinitoai 体现出的另一个思路,是借助浏览器本身更底层的输入能力来完成这件事。

它不是只追求“事件触发成功”,而是尽量让整条输入链路更像浏览器内核真正接收到的一次用户操作。

这也是为什么真实浏览器扩展,在某些交互研究里会比纯脚本环境更有参考价值。


四、为什么还需要页面状态机

很多自动化脚本失败,不是因为不会点击,而是因为根本不知道自己现在处在什么页面状态

比如同一个流程里,页面可能处于:

  • 正常表单页
  • 全页验证页
  • 内嵌验证组件页
  • 广告弹窗页
  • 错误页
  • 验证完成后的业务页

如果脚本完全靠固定等待时间:

打开页面 -> 等 3 秒 -> 点击 -> 再等 5 秒

那只要页面慢一点、结构变一点、弹一个额外层,它就很容易乱套。

所以更稳的做法,是建立页面状态机:

  • 先判断当前页面属于哪种状态
  • 再决定是否该点击、该等、该继续,还是该终止

这类设计虽然看着麻烦,但也是项目能长期活下来的关键。


五、为什么“结果判断”不能只看界面变化

研究验证流程时,还有一个特别容易忽略的问题:

你怎么知道自己真的成功了。

很多初学者会盯着界面看:

  • 勾选框亮了没
  • 文本变了没
  • 页面跳转了没

但这些都可能不够稳。

更靠谱的方式,通常是去找验证通过后的关键状态信号。

在这类机制里,常见信号包括:

  • 隐藏字段里出现有效 token
  • 页面 DOM 出现成功标记
  • 后续业务区域解锁
  • 网络请求状态变化

也就是说,真正稳的判断标准,往往不只是“看起来像成功了”,而是“页面内部已经出现可验证的成功状态”。


六、这类项目真正值得借鉴的地方

如果把表层细节都拿掉,Infinitoai 这类项目最有价值的,其实是下面这几个工程思路。

1. 尽早注入,抢执行时机

很多关键补丁如果注入晚了,就已经失去意义。

2. 进入正确上下文

浏览器扩展不是随便往页面丢段脚本就完事。主世界、隔离世界、iframe、子 frame,这些差别都会直接影响结果。

3. 输入不只讲“能点”,还讲“像不像”

在验证场景里,行为外观、事件属性和触发链路都很重要。

4. 建立状态机,而不是迷信固定等待

固定 sleep 很省事,但脆得像纸。

5. 用可验证信号判断成功

只看 UI 动画,远不如看真实状态变化可靠。


七、它的局限也很明显

这类方案不是万能钥匙。

它的前提条件本来就很强:

  • 必须在真实浏览器环境中运行
  • 必须依赖扩展能力
  • 必须贴近页面上下文
  • 必须对具体站点流程有较强适配

换句话说,它更像是一种浏览器交互研究样本,而不是一个适用于所有网站、所有环境的通用模板。

一旦离开真实浏览器,很多前提就不存在了。

总结

如果只从机制层面看,Infinitoai 给人的启发其实很清楚:

浏览器验证的本质,早就不只是“点没点按钮”,而是对环境、输入、上下文和状态变化的综合判断。

所以这类项目真正值得看的,并不是某一个“神奇点击”,而是它怎么把下面这些东西拼起来:

  • 真实浏览器环境
  • 更自然的事件外观
  • 正确的注入时机
  • 页面状态感知
  • 结果信号判断

把这些拼完整,很多原本看起来玄学的验证问题,就会一下子变得具体很多。

Chrome 扩展 Cloudflare Turnstile 浏览器 安全分析