Obscura Stealth 模式——指纹伪装、TLS 指纹与反检测原理
Obscura Stealth 模式的实现原理:内置浏览器 Profile 池、wreq BoringSSL TLS 指纹伪装、Tracker 拦截、身份一致性配置。
为什么自动化流量容易被检测
一个无头浏览器被检测出来,通常不是某一个特征暴露的,而是多个层面联合暴露:
- TLS 层:Go 或 Python 的 HTTP 库发送的 TLS ClientHello 与 Chrome 差异明显(密码套件顺序、ALPN 扩展、椭圆曲线)
- JS API 层:
navigator.webdriver为true、Function.prototype.toString返回非原生代码 - navigator 一致性:
userAgent是Mozilla/5.0...但platform是Linux、userAgentData缺失 - 行为模式:缺少对
canvas、audio、WebGL等指纹 API 的正常响应 - 网络关联:IP 地址来自数据中心段,与浏览器指纹的地理信息不匹配
Obscura Stealth 模式从架构层面解决了前四个问题。第五个(IP 与身份的地理关联)需要配合代理一起处理,Stealth 本身不解决出口 IP 问题。
内置浏览器 Profile 池
Obscura 内置了一组真实浏览器 Profile(Windows 与 macOS 混合,近期 Chrome 版本)。每个 Profile 内部保持一致:navigator.platform、userAgentData(平台与平台版本)、UA 字符串、WebGL/GPU renderer 四者互相吻合。Windows Profile 报告 ANGLE Direct3D11 renderer,macOS Profile 报告 ANGLE Metal renderer——这正是真实 Chrome 在对应平台上的行为。
这种内部一致性是反检测的关键。很多简易伪装方案只改了 UA 字符串,但 navigator.platform 和 GPU renderer 仍是底层库的默认值,检测脚本只要交叉比对就能识破。
默认情况下使用单一稳定的 Profile。环境变量控制 Profile 选择:
# 锁定到特定 Profile(按索引)
OBSCURA_PROFILE=2 obscura serve
# 随机轮换(每个浏览器上下文一个随机 Profile)
OBSCURA_ROTATE_PROFILE=1 obscura serve轮换身份本身也是一种信号——真实设备不会频繁变换指纹。默认不开启轮换。只有当一个出口 IP 长期对应多个独立身份时,才考虑开启。
TLS 指纹伪装
这是 Stealth 模式的核心能力。Obscura 通过 wreq crate 使用 BoringSSL(Google 维护的 OpenSSL 分支),配置与真实 Chrome 一致的:
- 密码套件顺序
- TLS 版本偏好
- ALPN 协议列表
- 椭圆曲线选择
# Stealth 模式依赖 wreq + BoringSSL,编译需要 cmake
cargo build --release --features stealth
# 启用后,TLS ClientHello 与真实 Chrome 一致
obscura fetch https://example.16yun.cn --stealth非 Stealth 模式下使用 rustls,不需要 cmake 或 OpenSSL。一个细节:脚本化的 fetch()/XHR 也走同一个 stealth 客户端,所以子资源请求和导航请求携带相同的 TLS 指纹,不会出现"主请求像 Chrome、子请求像 Rust 库"的不一致。
编译时注意:wreq 的 prefix-symbols 功能仅在 Linux 和 Android 上正确重命名 BoringSSL 导出符号,macOS 上使用不带 prefix-symbols 的配置。
JS API 层伪装
Stealth 模式在 V8 层做了以下伪装。
navigator.webdriver 隐藏
// 非 stealth:暴露自动化标志
navigator.webdriver // true
// stealth:与真实 Chrome 一致
navigator.webdriver // undefinedFunction.prototype.toString 伪装
// 非 stealth:toString 暴露代码内容
navigator.webdriver.toString() // "function webdriver() { [native code] }" 或自定义
// stealth:返回标准原生标记
Function.prototype.toString.call(navigator.webdriver) // "function () { [native code] }"event.isTrusted
Stealth 模式下分发的合成事件 event.isTrusted = true,不会被页面脚本识别为自动化事件。
Object.keys(window) 安全
隐藏的内部属性不会暴露在 Object.keys(window) 的返回结果中。
Tracker 拦截
Stealth 模式内置了 Peter Lowe 的广告与跟踪器域名列表,包含 3500+ 个域名。请求在离开发送前就在 net 层被拦截:
# Stealth 模式自动拦截以下类型的请求
# - 分析统计(Google Analytics、Mixpanel、Hotjar)
# - 广告网络(DoubleClick、Criteo、Adnxs)
# - 社交追踪(Facebook.net)
# - 指纹采集脚本支持的匹配模式:
- 精确匹配:
google-analytics.com - 子域名通配:
www.google-analytics.com、ssl.google-analytics.com
拦截发生在请求离开发送前,被拦的请求不会进入 V8 和 DOM,既节省带宽也避免触发第三方脚本的反爬逻辑。
身份一致性配置
光有 JS 层伪装不够。Stealth 的真正难点在于:timezone、geolocation、proxy 地区、Profile 必须四者一致,任何一个对不上都会成为检测信号。
# 完整反检测配置示例
OBSCURA_TIMEZONE=America/New_York \
OBSCURA_GEOLOCATION="40.7128,-74.0060" \
OBSCURA_PROFILE=2 \
obscura serve --stealth --proxy http://user:pass@proxy.16yun.cn:8888OBSCURA_TIMEZONE:默认 Europe/Berlin。设置后影响 Date.getTimezoneOffset、Intl.DateTimeFormat 和时区相关 API。引擎在 V8/ICU 读取时区之前就固定进程时区,保证 Date 的各个接口返回同一个区域。
OBSCURA_GEOLOCATION:配置 navigator.geolocation 返回的坐标,格式 lat,lon。不设置时返回一个固定默认值。
Profile / Timezone / Proxy 三者一致:如果你通过代理出口到纽约,Profile 应该为 macOS(常见于北美商业用户),时区为 America/New_York,地理位置为 40.7128,-74.0060。任何互相矛盾都会成为被检测的信号。
理解这一点很重要:Stealth 提供的是"一套自洽的身份",而不是"无法被识别的身份"。检测方做的往往是交叉验证——UA 说 Windows、时区说上海、IP 出口在法兰克福,三者对不上比单一特征异常更容易暴露。因此生产环境的反检测配置,核心工作不是开 Stealth,而是让 Profile、时区、地理、代理出口对齐到同一个真实身份画像。
验证你的反检测配置
Stealth 配好之后,第一步该做的是验证它真的生效,而不是直接上生产。几个自检手段:
检查 navigator.webdriver。用 --eval 在目标页执行:
obscura fetch https://example.16yun.cn --stealth --eval "navigator.webdriver"非 Stealth 会返回 true,Stealth 生效应返回 undefined。
检查 TLS 指纹。可以访问一个会回显 JA3 指纹的服务(需自行搭建或使用受信任的调试端点),对比 Stealth 开启前后的 ClientHello 哈希。Stealth 开启后应与真实 Chrome 的 JA3 一致,而不是 rustls 或 reqwest 的默认指纹。
交叉检查一致性。用一段 JS 把 navigator.userAgent、navigator.platform、navigator.userAgentData、时区(Intl.DateTimeFormat().resolvedOptions().timeZone)一次性打印出来,肉眼核对四者是否指向同一个身份画像。任何一个对不上(比如 UA 说 Windows、时区说上海),就是一个会被检测到的破绽。
对比有无 Stealth 的抓取成功率。在你的真实目标站上,分别用开启和关闭 Stealth 各跑一批请求,对比被拦截率。如果两者差不多,说明目标站的检测点不在 Stealth 覆盖的范围内(可能是 IP 信誉或行为分析),需要转向代理或行为模拟;如果 Stealth 开启后成功率明显提升,说明 TLS/JS 指纹是主要检测点,配置就是有效的。
Stealth 的局限性
Stealth 不处理以下场景:
- Cloudflare 交互式挑战(Turnstile、JS Challenge、CAPTCHA)
- Datadome 和 Akamai 主动 Bot 管理器
- 任何 CAPTCHA 系统
- 基于 IP 地址的速率限制(需要搭配代理)
对于这些场景,Stealth 需要和住宅代理、指纹浏览器等外部工具配合使用。
组合的最佳实践
# 生产级反检测配置(上海出口)
OBSCURA_TIMEZONE=Asia/Shanghai \
OBSCURA_GEOLOCATION="31.2304,121.4737" \
OBSCURA_PROFILE=0 \
obscura serve \
--stealth \
--proxy http://user:pass@proxy.16yun.cn:8888 \
--port 9222落地建议:
- 先定代理出口地区,再定身份:身份配置跟着 IP 走,而不是反过来。如果你用的是亿牛云海外住宅代理出口到美国,就把 Profile 选 macOS、时区设为美国时区、地理坐标设为美国城市。
- 保持身份稳定:同一个出口 IP 在一个会话周期内不要切换 Profile 或时区。频繁变换身份本身就是异常信号。
- 关闭轮换:除非你明确需要"一个 IP 对多个身份"的场景(少见),否则保留默认的单一稳定 Profile。
- 配合独享代理:共享代理池里的 IP 可能已经被其他人用过并被目标站标记。对反检测要求高的场景,独享代理的纯净度更有保障。
总结
Obscura Stealth 从四个层面构建反检测能力:
- TLS 层:BoringSSL wreq 客户端,指纹与 Chrome 一致
- Profile 层:内置真实浏览器 Profile 池,navigator 属性内部一致
- JS API 层:webdriver 隐藏、native code 伪装、event.isTrusted
- 网络层:3500+ 域名 Tracker 拦截,在请求离开前阻断
它不是万能的反检测方案,但对于绝大多数基于 JS 特征检测和 TLS 指纹识别的防护系统,Stealth 模式足以绕过。真正决定反检测效果的,是 Profile、时区、地理、代理出口四者是否对齐到同一个自洽身份。
需要企业代理方案?
我们可根据目标站点、并发规模与稳定性目标提供定制方案。