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.valueHe();// CDP 卡片y.valueyieldVe();// Dev Tool 卡片if(f.value)n.valuefalse;if(y.value)n.valuefalse;页面展示关系f控制Chrome DevTools Protocol 检测区域里的CDP结果。y控制同一区域里的Dev Tool结果。顶部CDP摘要项使用f || y。任一结果为true总检测结果进入异常状态。检测 1CDP / Error.stack getter还原后的核心逻辑functiondetectChromeDevToolsProtocol(){letdetectedfalse;consterrorObjectnewwindow.Error();window.Object.defineProperty(errorObject,stack,{configurable:false,enumerable:false,get:function(){detectedtrue;return;}});window.console.debug(errorObject);returndetected;}判定逻辑正常情况下只创建Error并传给console.debugstackgetter 不一定会被同步读取。某些 CDP/DevTools/自动化协议链路会为了展示或传输 console 参数而序列化Error对象。一旦序列化过程读取error.stackgetter 触发detected true。返回true表示 CDP 相关序列化副作用被观察到。这一条是同步探针BrowserScan 直接把返回值写入CDP卡片。检测 2Dev Tool / Worker debugger timing还原后的 Worker 代码onmessagefunction(){postMessage(before);debugger;postMessage(after);};主线程判定逻辑constblobnewBlob([workerCode],{type:application/javascript});consturlURL.createObjectURL(blob);constworkernewWorker(url);letbeforeAt;worker.onmessagefunction(event){if(event.databefore){beforeAtperformance.now();setTimeout(()resolve(true),500);}elseif(event.dataafter){constelapsedMsperformance.now()-beforeAt;resolve(elapsedMs100);}};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为正常。