Obscura Stealth 模式——指纹伪装、TLS 指纹与反检测原理

Obscura Stealth 模式的实现原理:内置浏览器 Profile 池、wreq BoringSSL TLS 指纹伪装、Tracker 拦截、身份一致性配置。

亿牛云技术团队2026年7月3日7 分钟阅读

为什么自动化流量容易被检测

一个无头浏览器被检测出来,通常不是某一个特征暴露的,而是多个层面联合暴露:

  • TLS 层:Go 或 Python 的 HTTP 库发送的 TLS ClientHello 与 Chrome 差异明显(密码套件顺序、ALPN 扩展、椭圆曲线)
  • JS API 层navigator.webdrivertrueFunction.prototype.toString 返回非原生代码
  • navigator 一致性userAgentMozilla/5.0...platformLinuxuserAgentData 缺失
  • 行为模式:缺少对 canvasaudioWebGL 等指纹 API 的正常响应
  • 网络关联:IP 地址来自数据中心段,与浏览器指纹的地理信息不匹配

Obscura Stealth 模式从架构层面解决了前四个问题。第五个(IP 与身份的地理关联)需要配合代理一起处理,Stealth 本身不解决出口 IP 问题。

内置浏览器 Profile 池

Obscura 内置了一组真实浏览器 Profile(Windows 与 macOS 混合,近期 Chrome 版本)。每个 Profile 内部保持一致:navigator.platformuserAgentData(平台与平台版本)、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 // undefined

Function.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.comssl.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:8888

OBSCURA_TIMEZONE:默认 Europe/Berlin。设置后影响 Date.getTimezoneOffsetIntl.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.userAgentnavigator.platformnavigator.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 从四个层面构建反检测能力:

  1. TLS 层:BoringSSL wreq 客户端,指纹与 Chrome 一致
  2. Profile 层:内置真实浏览器 Profile 池,navigator 属性内部一致
  3. JS API 层:webdriver 隐藏、native code 伪装、event.isTrusted
  4. 网络层:3500+ 域名 Tracker 拦截,在请求离开前阻断

它不是万能的反检测方案,但对于绝大多数基于 JS 特征检测和 TLS 指纹识别的防护系统,Stealth 模式足以绕过。真正决定反检测效果的,是 Profile、时区、地理、代理出口四者是否对齐到同一个自洽身份。

需要企业代理方案?

我们可根据目标站点、并发规模与稳定性目标提供定制方案。