跳到主要内容

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

Note

一个"会点复选框"的脚本和一个"看起来像真人"的脚本, 差距究竟在哪一层? 是注入时机, 是事件来源, 还是页面状态感知?

0x00 背景

原文以开源项目 Infinitoai(一个 Chrome 扩展)为切入点, 不讲"怎么一把梭", 而是拆解真实浏览器里的扩展为什么比普通脚本更接近真人环境. 它值得被单独拆解的三个理由:

  • 它把"验证机制"从"点没点到"提升为"环境 + 输入 + 上下文 + 状态变化"的综合判断, 这是理解一切浏览器验证(包括 Turnstile/reCAPTCHA)的统一模型.
  • 它给出的三个注入条件(document_start / MAIN world / all_frames)是浏览器逆向中最容易被忽略、却直接决定成败的上下文问题.
  • 它提出的"可信事件" vs "普通点击"、"状态机" vs "固定等待"、"可验证信号" vs "界面变化", 是通用自动化工程方法论, 与 AI Agent 设计直接相通.

边界说明: 原文本身是机制研究, 本文同样只停留在机制层的解释, 不提供可执行绕过步骤.

0x01 核心结论

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

普通脚本很脆、无头环境容易暴露, 真实浏览器里的扩展更接近"自然用户环境", 因为:

  1. 更真实的浏览器指纹: 真实 Chrome 内核 + 真实渲染栈.
  2. 更接近自然用户的 API 行为: 页面脚本与扩展共享真实运行环境.
  3. 可以借助浏览器内部能力派发输入事件: 比 element.click() / dispatchEvent 更底层的输入链路.

原文拆出的五个工程思路(这是全篇骨架):

  1. 尽早注入, 抢执行时机 — 关键补丁注入晚了就失去意义.
  2. 进入正确上下文 — 主世界/隔离世界/iframe/子 frame 的差别直接影响结果.
  3. 输入不只讲"能点", 还讲"像不像" — 事件属性、触发链路、坐标关系.
  4. 建立状态机, 而不是迷信固定等待 — 固定 sleep 脆得像纸.
  5. 用可验证信号判断成功 — 只看 UI 动画, 不如看真实状态变化.

0x02 关键细节

2.1 项目结构透露的分层思路

Infinitoai 不是单点技巧, 而是分层设计:

  • background.js: 流程编排.
  • 内容脚本: 与页面交互.
  • 专门的补丁脚本: 在页面很早阶段注入.
  • 侧边栏: 控制面板.

这说明成熟浏览器自动化项目的共性:把"环境修补、页面感知、事件派发、结果判断"拆成几层, 而不是一个暴力脚本硬点.

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

Turnstile 会观察鼠标事件的 clientX / clientY / screenX / screenY. 真实用户点击时这些值之间有合理关系; 程序构造的合成事件常有奇怪特征:

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

所以需要在页面脚本执行前尽早注入补丁修正坐标属性. 原文强调的三个注入条件:

{
"run_at": "document_start",
"world": "MAIN",
"all_frames": true
}
json
  • document_start: 越早越好, 赶在页面主要逻辑运行前.
  • MAIN: 进入页面主世界, 而不是只活在扩展自己的隔离环境.
  • all_frames: 验证组件常在 iframe 里, 不进 frame 基本白搭.

这组配置本身就是对"验证机制对上下文位置有多敏感"的最好说明.

2.3 "可信事件"比"普通点击"更重要

普通前端触发方式(element.click(), dispatchEvent(new MouseEvent(...)))在很多业务场景够用, 但反机器人验证不仅看"有没有发出点击", 还看点击是否足够可信:

  • 事件是否来自浏览器内核真正接收的用户操作.
  • 坐标关系、触发链路、时序是否自然.

Infinitoai 的思路是借助浏览器本身更底层的输入能力(CDP / 扩展能力)完成输入, 让整条输入链路更像浏览器内核接收到的一次真实操作, 而不是只追求"事件触发成功".

这对 AI Agent 自动化的启示: 当目标系统的反检测只看"行为外观"时, 用真实浏览器能力派发事件, 优于在 JS 层伪造事件.

2.4 页面状态机: 知道自己处在哪

自动化脚本失败的主因不是"不会点击", 而是"不知道自己现在处在什么页面状态". 同一流程里页面可能处于:

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

固定等待(打开页面 -> 等3秒 -> 点击 -> 等5秒)在页面慢一点、结构变一点、弹额外层时就会乱套. 更稳的做法:

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

这就是把"流程"升级为"状态机" — 与 LLM Agent 中"先感知当前 tool 执行状态再决定下一步"同构.

2.5 结果判断: 不能只看界面变化

很多初学者盯着界面看: 勾选框亮了没、文本变了没、页面跳转了没. 这些都可能不稳. 更靠谱的是找验证通过后的关键状态信号:

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

真正稳的判断标准是"页面内部已经出现可验证的成功状态", 而不是"看起来像成功了". 这对应到 001-CF过盾工程 中"双重成功判断 + 等待 Cookie 写入"的工程细节.

2.6 局限

这类方案不是万能钥匙, 前提条件很强:

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

离开真实浏览器, 很多前提就不存在了. 它更像一种浏览器交互研究样本, 而不是适用所有网站、所有环境的通用模板.

0x03 拓展升华展望

你的自动化流程, 是"会执行动作", 还是"像真实用户一样被系统感知"?

  • 如果你只追求"事件触发成功", 那么 element.click() 就够 — 但检测方也在看你的坐标、时序和上下文.
  • 如果你追求"输入链路、页面状态、结果信号"三者的自洽, 那你就已经把验证机制当成一个需要逆向建模的系统, 而不是一道题.

把一个"会点复选框"的脚本和一个"看起来像真人"的脚本放在一起比, 先站到更高一层看: 浏览器验证的判据早就不在动作本身, 而在环境、输入、上下文与状态变化是否互相自洽.

事实层面 … 原文的五个工程判断都能在 Infinitoai 的代码结构里找到落点: document_start / MAIN world / all_frames 三个注入条件是浏览器扩展机制下的客观约束, 可信事件与普通点击的区别在于输入是否经由浏览器内核接收, 页面状态机与可验证成功信号则来自原文对失败案例的归纳.

个人判断 … 这套五块拼图不会停留在"过验证"这一件事上. 当 Agent 开始操作真实网页, 它面对的是同一套判据: 谁在感知页面状态、输入链路是否可信、成功信号是否可验证, 决定了自动化能否从一个会执行动作的脚本, 变成被系统当成真实用户来感知的流程. 我倾向于认为, 后面真正稀缺的不是更隐蔽的注入技巧, 而是把"环境、输入、上下文、状态、信号"这五件事写成一套可复用观察框架的能力.

0x04 参考来源

给 AI 买点 Token:
Alipay IconQR Code
Wechat IconQR Code
本文遵循 CC CC 4.0 BY-SA 版权协议, 转载请标明出处
Loading Comments...