浏览器CDP自动化检测技术-Error和Worker
BrowserScan Bot Detection CDP 技术报告
结论
目标页https://www.browserscan.net/zh/bot-detection的 CDP 相关检测不是哈希类纯算,而是两条浏览器运行时探针:
CDP:利用Error.stackgetter 被console.debug(error)序列化时触发的副作用。Dev Tool:在Worker中执行debugger,用before/after两次消息的时间差判断是否被开发者工具或调试协议暂停。
可复刻代码已写入 browserscan_bot_cdp_detection.js。它保留 BrowserScan 的判定阈值:Dev Tool时间差大于100ms判定异常,after消息500ms内未返回也判定异常。
源码定位
本次分析使用已落盘响应脚本:
- 页面组件:
trace_browserscan_bot_20260609_221758/response_9684_8589934601_7.BtL2bcz0.js.decoded.js - 检测函数:
trace_browserscan_bot_20260609_221758/response_9684_8589934602_2.hd4NLkmt.js.decoded.js
组件导入关系:
import{rasHe,sasVe}from"./hd4NLkmt.js";页面执行关系:
f.value=He();// CDP 卡片y.value=yieldVe();// Dev Tool 卡片if(f.value)n.value=false;if(y.value)n.value=false;页面展示关系:
f控制Chrome DevTools Protocol 检测区域里的CDP结果。y控制同一区域里的Dev Tool结果。- 顶部
CDP摘要项使用f || y。 - 任一结果为
true,总检测结果进入异常状态。
检测 1:CDP / Error.stack getter
还原后的核心逻辑:
functiondetectChromeDevToolsProtocol(){letdetected=false;consterrorObject=newwindow.Error();window.Object.defineProperty(errorObject,"stack",{configurable:false,enumerable:false,get:function(){detected=true;return"";}});window.console.debug(errorObject);returndetected;}判定逻辑:
- 正常情况下,只创建
Error并传给console.debug,stackgetter 不一定会被同步读取。 - 某些 CDP/DevTools/自动化协议链路会为了展示或传输 console 参数而序列化
Error对象。 - 一旦序列化过程读取
error.stack,getter 触发,detected = true。 - 返回
true表示 CDP 相关序列化副作用被观察到。
这一条是同步探针,BrowserScan 直接把返回值写入CDP卡片。
检测 2:Dev Tool / Worker debugger timing
还原后的 Worker 代码:
onmessage=function(){postMessage("before");debugger;postMessage("after");};主线程判定逻辑:
constblob=newBlob([workerCode],{type:"application/javascript"});consturl=URL.createObjectURL(blob);constworker=newWorker(url);letbeforeAt;worker.onmessage=function(event){if(event.data==="before"){beforeAt=performance.now();setTimeout(()=>resolve(true),500);}elseif(event.data==="after"){constelapsedMs=performance.now()-beforeAt;resolve(elapsedMs>100);}};worker.postMessage("");判定逻辑:
- Worker 收到消息后先发
before。 - 随后执行
debugger。 - 如果没有调试器介入,Worker 很快继续执行并发出
after。 - 主线程计算
after - before,大于100ms判定异常。 - 如果
after在500ms内没有到达,也判定异常。
这一条是异步探针,BrowserScan 通过yield Ve()等待结果后写入Dev Tool卡片。
纯算边界
这里的“纯算”不能理解成脱离浏览器环境的固定公式。CDP 检测的输入不是字符串、canvas 图像或可枚举参数,而是运行时副作用:
console.debug是否触发Error.stackgetter,取决于控制台实现、DevTools/CDP 是否附着、自动化框架是否拦截 console 参数。debugger是否造成 Worker 暂停,取决于调试器状态、断点策略、Worker 调试支持和事件循环调度。- 因此 JS 代码可以纯复刻判定树,但最终真假必须在目标浏览器上下文里执行得到。
可稳定复刻的部分是:
- getter 设置方式;
- console 调用方式;
- Worker 源码;
100ms阈值;500ms兜底超时;CDP || Dev Tool的页面聚合逻辑。
产物说明
browserscan_bot_cdp_detection.js 暴露全局对象:
window.BrowserScanBotCDP主要接口:
BrowserScanBotCDP.detectChromeDevToolsProtocol(window);awaitBrowserScanBotCDP.detectDevToolDebuggerTiming(window);awaitBrowserScanBotCDP.collect(window);collect()返回结构:
{cdp:{name:"CDP",detected:false,...},devTool:{name:"Dev Tool",detected:false,elapsedMs:"<runtime number>",...},detected:false,siteCompatible:{cdp:false,devTool:false,abnormal:false}}其中siteCompatible.cdp对齐页面CDP卡片,siteCompatible.devTool对齐页面Dev Tool卡片。
验证结果
验证脚本:ruyipage_verify_browserscan_bot_cdp.py
验证方式:
node--check.\browserscan_bot_cdp_detection.js python.\ruyipage_verify_browserscan_bot_cdp.py实测页面 CDP 区域文本:
Chrome DevTools Protocol 检测 ... CDP 正常 Dev Tool 正常本地复刻函数返回:
{"cdp":false,"devTool":false,"abnormal":false}页面文本与复刻函数一致:CDP为正常,Dev Tool为正常。
