检测无头浏览器:Playwright、Puppeteer 及其他
我们的 Bot Detection 引擎通过信号不一致、缺失的 API 以及机器人无法伪造的行为模式,识别 15 种以上的自动化框架。
无头浏览器是复杂网页抓取、撞库攻击和欺诈操作的首选武器。与简单的 HTTP 客户端不同,无头浏览器能执行 JavaScript、渲染页面并支持现代 Web API——这使它们更难被检测。我们的 Bot Detection 引擎使用多种独立的检测方法,以近乎零误报的方式识别 15 种以上的自动化框架。
浏览器自动化的演进
浏览器自动化早已不再是简单的 curl 脚本。像 Playwright、Puppeteer 和 Selenium WebDriver 这样的现代工具,能以无头模式控制真实的浏览器引擎——Chromium、Firefox 或 WebKit。它们像有头浏览器一样执行 JavaScript、处理 CSS、渲染 canvas 元素并处理 WebGL 查询。这使它们对那些仅检查 JavaScript 执行能力的检测方法而言是隐形的。
最新一代工具走得更远。Playwright 的隐身模式修补了传统机器人检测所依赖的许多信号。Puppeteer-extra-plugin-stealth 会修改 navigator 属性、覆盖 WebGL 厂商字符串并伪造用户交互事件。这些反检测手段在机器人运营者与检测系统之间催生了一场军备竞赛。
检测方法一:WebDriver 标志分析
当浏览器由自动化程序控制时,navigator.webdriver 属性会被设为 true。早期检测只需检查这个属性即可。但现代隐身工具会删除或覆盖它。我们的检测更进一步——不仅检查属性值,还检查其属性描述符、它在原型链中的存在情况,以及是否有人试图重新定义它。我们还会检查相关属性,例如伴随 WebDriver 覆盖而出现的 navigator.plugins 长度异常。
检测方法二:Chrome DevTools Protocol 痕迹
Playwright 和 Puppeteer 通过 Chrome DevTools Protocol(CDP)控制浏览器。即使隐身模式处于激活状态,CDP 也会在运行时留下痕迹:特定的全局变量、被修改的 getter 函数,以及 Window 和 Navigator 对象上被更改的属性描述符。我们使用对简单覆盖具有抵抗力的技术来探测这些痕迹。
检测方法三:无头浏览器指纹识别
无头 Chrome 与有头 Chrome 的能力集不同。它缺少某些浏览器插件,对某些 CSS 属性的渲染特性不同,并且对某些 MediaQuery 结果报告不同的值。我们维护一个已知无头浏览器特征的数据库,并将传入的指纹与其进行比对。
关键的无头指标包括:缺失 chrome.runtime(有头 Chrome 中存在,但无头模式中缺失)、长度为零的 navigator.plugins 数组、在先前版本中与无头模式相关联的特定 user agent 模式,以及无头 Chrome 处理 iframe 安全上下文方式上的差异。
检测方法四:Eval 长度分析
不同的 JavaScript 引擎对内置函数有不同的实现,而这些实现有不同的字符串表示。通过检查 Function.prototype.toString.call(eval) 的长度并将其与各浏览器引擎的已知值进行比较,我们可以检测出环境伪装——例如,一个假装成 Firefox 的无头 Chrome 实例。
检测方法五:TLS 交叉验证
正如我们在 TLS 指纹识别文章中所讨论的,TLS Client Hello 消息会揭示发起连接的真实浏览器或 HTTP 库。当 Playwright 脚本控制 Chrome 时,TLS 指纹与 Chrome 匹配——这是预期的。但当一个自定义机器人使用 Python 的 requests 库或 Go 的 net/http 时,无论发送什么 user agent 字符串,TLS 指纹都会揭穿这一伪装。
检测方法六:时序与行为分析
真实用户在交互时序上表现出自然的变化。他们移动鼠标时是曲线而非直线。他们在点击前会停顿。他们以不同的速度滚动。自动化工具即使模拟人类行为,也会产生统计上可区分的模式——过于一致的时序、完全线性的鼠标轨迹以及不自然的滚动速度。
我们在指纹识别过程本身中收集最少量的行为信号——API 调用的时序、信号收集的顺序,以及某些浏览器 API 的响应速度。这些微行为信号很难被自动化工具伪造,因为它们取决于实际的执行环境,而非可覆盖的属性。
检测方法七:权限与 API 不一致
真实浏览器具有一致的权限状态和 API 可用性。一个声称支持通知却没有 Notification 构造函数的浏览器,或者报告了某个特定屏幕分辨率却从 window.screen 和 CSS 媒体查询返回不同值的浏览器,正在表现出表明被篡改或被模拟的不一致。
我们检查数十个这样的交叉验证点,寻找当自动化工具有选择地覆盖某些信号却未能在所有相关 API 之间保持一致时所产生的矛盾。
检测方法八:虚拟机与模拟检测
许多机器人操作运行在虚拟机或云实例中。虽然这本身并不能证明是自动化,但当与其他指标结合时,它是一个强有力的信号。我们通过以下方式检测虚拟机:包含虚拟机相关关键词的 WebGL renderer 字符串(如 “llvmpipe” 或 “SwiftShader”)、与消费者设备不一致的硬件特征(恰好 2 个 CPU 核心和 2GB 内存——常见的虚拟机默认配置),以及已知的云服务提供商 IP 段。
多方法优势
每种检测方法单独来看都有局限——一个复杂的机器人运营者可能规避任何单一方法。但要同时规避所有方法,同时在所有方法之间保持交叉验证的一致性,代价高得令人望而却步。开发和维护一个能通过所有检查的机器人的成本,超过了大多数机器人操作的经济价值。
近乎零误报
我们的检测对搜索引擎机器人(Googlebot、Bingbot 等)采用白名单模型,通过反向 DNS 进行验证,对其他流量则采用多信号模型。在将流量归类为自动化之前,我们要求多个相互印证的信号。这种保守的方法确保了误报率低于 0.1%——已在数十亿次生产事件中得到验证。