浏览器反检测技术(二):GPU 管线、按键熵与 Client Hints
输入事件熵、GPU 渲染管线差异、Client Hints 头部、CDP Runtime 检测——2026 年还在测 navigator.webdriver 的反爬系统已经过时了。
经典检测信号在 2026 年还有效吗
先给一个直接的答案:单个信号基本都失效了,组合信号才是检测的核心。
navigator.webdriver——2018 年就被 puppeteer-extra-plugin-stealth 攻破了。
window.chrome 缺失——2020 年被 stealth 插件覆盖。
Plugin 数组为空——2019 年被补丁。
WebGL VENDOR/RENDERER——stealth 插件通过覆盖 getParameter 返回值来绕过。
User-Agent——Client Hints 系统已经取代了旧式的浏览器宣告方式。
每一个静态属性检测都有对应的 stealth 插件来反制。2026 年的检测系统已经转移到了无法通过简单属性覆盖来绕过的信号上。
信号一:输入事件熵
这是目前最可靠的单一信号。真实人类的输入——即使是打字很快的人——产生的是一串具有可预测物理特征的事件流。
鼠标移动:人类的鼠标移动不是直线。每次移动有微小的抖动,加速度曲线遵循 Fitts 定律指向目标。CDP 驱动的鼠标移动即使经过 stealth 插件处理,产生的也是合成事件。特征:
- CDP 合成移动:整数像素坐标、完美的直线或完美曲线、每次移动的时间间隔相同
- 真实人类移动:亚像素坐标、轨迹有随机抖动、速度根据距离变化
键盘输入:真实打字的按键按下和释放间隔在 30-120ms 之间波动,不同按键的停留时间不同(空格键通常比字母键短)。CDP 发送的 keyDown/keyUp 事件的时间间隔要么完全一致,要么过于随机(没有人类按键的自然分布模式)。
具体来说,一个能够用来检测的特征是:有意义的操作(登录、提交、支付)之前如果没有鼠标移动事件,那这个会话 99% 是机器人。
检测逻辑(伪代码):
if session has meaningful_action (login/checkout/submit):
if mouseMoveCount == 0:
return "bot - no mouse movement before action"
if mouseMoveEntropy < threshold:
return "bot - insufficient movement entropy"
if keyDwellStdDev < threshold:
return "bot - keystroke timing too uniform"信号二:GPU 渲染管线
无头 Chrome 和有头 Chrome 的 GPU 渲染管线不同。即使使用 --use-gl=swiftshader 或硬件加速模拟,差异仍然存在。
具体差异包括:
Canvas 文本渲染的亚像素定位。同样的文本,在无头模式和完整模式下渲染,字符的亚像素位置有系统性的偏差。这种偏差是稳定的、可预测的。检测系统可以维护一个"已知的 Canvas 渲染参考值 → 判断为 CDP 驱动 Chrome"的哈希表。
贝塞尔曲线走样模式。Canvas 路径渲染中的贝塞尔曲线,在无头模式下的锯齿(Aliasing)模式与完整模式不同。这种差异可以通过与已知参考值对比来检测。
WebGL readPixels 输出。对一个受控场景调用 readPixels(),头无头模式的输出字节存在稳定的差异。
Stealth 插件不触及 GPU 管线,因为要修改 GPU 输出必须替换渲染器本身,而替换的渲染器本身也会产生可检测的差异。
信号三:Client Hints
Chrome 的 User-Agent 缩减(User-Agent Reduction)项目改变了浏览器宣告自己的方式。旧式的 UA 字符串 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 ... 已经失去了大部分信息量。Chrome 现在默认发送一组最小的 Client Hints 头部:
Sec-CH-UA: "Google Chrome";v="124", "Chromium";v="124"
Sec-CH-UA-Mobile: ?0
Sec-CH-UA-Platform: "Windows"如果服务器想要更多信息,它通过 Accept-CH 响应头来请求。Chrome 然后决定是否发送高熵数据:
Accept-CH: Sec-CH-UA-Arch, Sec-CH-UA-Full-Version-List, Sec-CH-UA-Model这是一个结构化的 opt-in 交换协议,而不是被动的数据转储。
对于检测系统来说,这意味着:
- 旧式的 UA 欺骗已经不够了——Client Hints 头部必须与声称的浏览器版本一致
- 如果 Sec-CH-UA 声称 Chrome 124,但浏览器行为像 Chrome 130,检测系统可以判定不一致
- 高熵数据的值(平台、架构、设备型号)必须与系统的其他指纹特征吻合
信号四:CDP Runtime 检测
即使经过了所有的 stealth 补丁,Chrome DevTools Protocol 仍然在运行时留下了一个微小的但可测量的签名。
具体方法是:在 getter 中调用 console.debug 并带 %c 格式参数,然后测量这个调用的时间差异。当 DevTools 附加到页面时(CDP 的本质就是 DevTools 协议),这个调用会产生一个约 0.3ms 的可测量延迟。
这个信号需要在几个月内重新验证——Chromium 的 CDP 团队会修补已知的检测手法——但截至 2026 年中,多个变种仍然有效。
组合评分才是关键
单个信号都有误报:
- 触摸设备用户没有鼠标移动事件
- 某些 GPU 在无头模式下表现异常
- VPN 用户可能看起来像机器人
正确的做法是评分后分级处理,而不是单一信号阻断:
score = calculate_automation_score(input_entropy, gpu_pipeline, client_hints, cdp_signal)
if score < 0.3:
action = "allow"
elif score < 0.6:
action = "step_up" # CAPTCHA 或邮箱确认
elif score < 0.9:
action = "hard_challenge" # 蜜罐或二次验证
else:
action = "block"这对自动化意味着什么
如果你在维护浏览器自动化的采集通道,2026 年的现实是:
传输层指纹(上篇)和应用层行为信号(本篇)的组合让检测系统比以往更难绕过。只靠 stealth plugin 已经不够。只靠 C++ 引擎级反检测也不够。需要的是传输层、应用层、行为模式三者的一致性。
下一篇文章会分析这个一致性问题:为什么长期稳定的环境比频繁轮换存活更久。
需要企业代理方案?
我们可根据目标站点、并发规模与稳定性目标提供定制方案。