Chrome扩展Hook Navigator对象遭反机器人检测,如何解决?
问题概述
我编写Chrome扩展篡改Navigator对象属性用于反指纹识别实验,采用相关技术修改了User-Agent且伪造值与真实UA完全一致,但在bot检测页面仍被识别为机器人,求原因及解决办法。
提供的代码
manifest.json
{ "manifest_version": 3, "name": "Helper", "description": "Base Level Extension", "version": "1.0", "background": {"service_worker": "bg.js"}, "host_permissions": ["<all_urls>"], "permissions": [ "scripting", "contentSettings", "tabs", "storage", "declarativeNetRequest", "declarativeNetRequestWithHostAccess" ], "declarative_net_request": { "rule_resources": [{ "id": "ruleset", "enabled": true, "path": "rules.json" }] }, "action": { "default_popup": "helper.html", "default_icon": "helper.png" } }
bg.js
chrome.runtime.onInstalled.addListener(async () => { const old = await chrome.scripting.getRegisteredContentScripts(); if (old[0]) await chrome.scripting.unregisterContentScripts({ids: old.map(s => s.id)}); await chrome.scripting.registerContentScripts([{ id: 'write', js: ['write.js'], matches: ['<all_urls>'], runAt: 'document_start', world: 'MAIN', }]);
write.js
var navigator = window.navigator; var modifiedNavigator; if ('userAgent' in Navigator.prototype) { modifiedNavigator = Navigator.prototype; } else { modifiedNavigator = Object.create(navigator); Object.defineProperty(window, 'navigator', { value: modifiedNavigator, configurable: false, enumerable: false, writable: false }); } console.info(navigator.userAgent) console.info(navigator.appName) console.info(navigator.appVersion) console.info(navigator.platform) var ua = navigator.userAgent // I tried this modifiedNavigator.__defineGetter__('userAgent', function () { return ua; }); // As well as this Object.defineProperties(modifiedNavigator, { userAgent: { value: navigator.userAgent.replace(/\([^)]+\)/, 'Windows NT 5.1'), configurable: false, enumerable: true, writable: false } });
原因分析
- 仅修改User-Agent不全面:指纹检测依赖的不只是User-Agent,还会校验
platform、appVersion、webdriver、vendor等多个Navigator属性,甚至属性的描述符(可配置性、枚举性),单一属性修改会出现特征不一致。 - 请求头与页面UA不匹配:你只修改了页面内的Navigator.userAgent,但HTTP请求头中的User-Agent还是原始值,检测系统会对比这两个值,不一致直接判定为异常。
- 属性修改方式存在漏洞:使用
__defineGetter__或直接覆盖属性的方式,会改变属性的原始描述符(比如可配置性),现代指纹检测会通过Object.getOwnPropertyDescriptor检查属性特征,发现篡改痕迹。 - 未处理
webdriver属性:多数bot检测会检查navigator.webdriver,即便在非自动化环境,扩展修改Navigator的操作可能导致该属性状态异常,或未强制设置为符合正常浏览器的false。
解决办法
1. 同步修改请求头与页面UA
通过declarativeNetRequest修改HTTP请求头的User-Agent,确保和页面内伪造值完全一致。创建rules.json文件:
[ { "id": 1, "priority": 1, "action": { "type": "modifyHeaders", "requestHeaders": [ { "header": "User-Agent", "operation": "set", "value": "Mozilla/5.0 (Windows NT 5.1; rv:109.0) Gecko/20100101 Firefox/115.0" // 替换为你伪造的UA } ] }, "condition": { "urlFilter": "*", "resourceTypes": ["main_frame", "sub_frame", "stylesheet", "script", "image", "font", "object", "xmlhttprequest", "ping", "csp_report", "media", "websocket", "other"] } } ]
2. 全面篡改Navigator关键属性并模拟原生描述符
修改write.js,覆盖所有指纹检测常用属性,同时保留原生属性的描述符特征,避免被检测到篡改:
const originalNav = window.navigator; // 定义要伪造的属性值,确保UA与其他属性匹配 const fakeProps = { userAgent: originalNav.userAgent.replace(/\([^)]+\)/, 'Windows NT 5.1'), platform: 'Win32', appVersion: '5.0 (Windows)', webdriver: false, vendor: '', // 根据目标浏览器填写,比如Chrome是'Google Inc.' language: 'zh-CN' }; // 获取原生属性的描述符,用来模拟原始特征 const getOriginalDescriptor = (prop) => { return Object.getOwnPropertyDescriptor(originalNav, prop) || Object.getOwnPropertyDescriptor(Navigator.prototype, prop); }; // 逐个修改属性,保留原生描述符的可配置、枚举等特征 Object.keys(fakeProps).forEach(prop => { const originalDesc = getOriginalDescriptor(prop); if (!originalDesc) return; Object.defineProperty(Navigator.prototype, prop, { ...originalDesc, get: () => fakeProps[prop], value: fakeProps[prop], configurable: originalDesc.configurable !== undefined ? originalDesc.configurable : false }); }); // 移除调试用的console输出,避免暴露痕迹
3. 确保修改时机足够早
保持runAt: 'document_start'和world: 'MAIN'的配置,确保脚本在页面任何检测代码运行前完成属性篡改。
4. 隐藏扩展相关痕迹
避免在MAIN world脚本中引入任何扩展专属API(如chrome对象),同时删除调试用的console输出,防止被检测到异常脚本行为。
内容的提问来源于stack exchange,提问作者Andreas Toresäter
相关产品推荐
相关产品推荐

