浏览器反检测技术(一):TLS 握手与 HTTP/2 帧——在 JS 执行之前你已被识别

TLS 握手指纹(JA3/JA4)、HTTP/2 Settings 帧特征、TCP 时间戳差异——在你控制浏览器之前,操作系统和网络栈已经把真实身份交出去了。

亿牛云技术团队2026年4月5日6 分钟阅读

传输层检测:你还没登录已经被标记了

如果你只关注 Camoufox 的 C++ 引擎级指纹覆盖和 Puppeteer Stealth Plugin 的 JS 垫片,说明你只防御了反检测的一部分。还有一大块防线你可能根本没意识到存在:传输层检测

传输层检测发生在浏览器执行任何 JavaScript 之前。你打开一个网站,在 HTML 下载完成、CSS 开始解析、JS 开始执行之前,客户端和服务器之间的 TLS 握手已经完成了。而这个握手过程本身携带了足够多的特征信息来判断对方是不是一个真实的浏览器。

这种检测方式的优势在于:它不在浏览器能控制的范围之内。

你在 JavaScript 里修改 navigator.webdriver、覆盖 Canvas 指纹、伪造 AudioContext 输出——但这些操作都发生在应用层,影响不了传输层的行为。TLS 握手是由操作系统和网络库完成的,不是由网页的 JavaScript 决定的。

JA3/JA4:TLS 握手指纹

TLS 握手过程中,客户端会发送一个 Client Hello 消息,其中包含:

  • 支持的 TLS 版本列表
  • 支持的密码套件列表
  • 支持的扩展列表(Extension)
  • 支持的椭圆曲线列表
  • 签名算法列表

这些参数的组合——不是单个参数的值,而是它们的排列组合——形成了 TLS 指纹。JA3 是这个指纹的经典实现:对 Client Hello 中的参数进行哈希,得到一个唯一标识符。

不同浏览器的 TLS 指纹不同:

  • Chrome 130 的 JA3 指纹:771,4865-4866-4867-...
  • Firefox 130 的 JA3 指纹:771,4865-4867-4866-...
  • curl 的 JA3 指纹:完全不同,因为它支持的密码套件少得多

curl 和 Chrome 的 TLS 指纹差异不只是密码套件数量的不同,还包括:

  • 扩展顺序不同:Chrome 有特定的扩展偏好顺序
  • ALPN 协议列表不同:Chrome 支持 h2(HTTP/2),curl 7.x 部分版本不支持
  • 椭圆曲线顺序不同:Chrome 优先使用 x25519,curl 可能是 prime256v1

JA4 是 JA3 的改进版本,增加了对 TLS 1.3 的支持和更细粒度的特征提取。

JA4 指纹:

t13d1516h2_8daaf6152771_02713d6af862
  • t13 = TLS 1.3
  • d15 = 支持 15 个密码套件
  • 16h2 = 支持 16 个扩展,包含 h2 协议
  • 后面的哈希值来自具体的参数值

使用 curl -sI https://example.16yun.cn 和 Chrome 访问同一个页面,服务器看到的 JA4 指纹完全不同。

HTTP/2 Settings 帧:比 TLS 更精细的信号

如果目标网站支持 HTTP/2(截至 2026 年,几乎所有主流网站都支持),在 TLS 握手完成后,客户端会发送一个 HTTP/2 Settings 帧。这个帧包含了客户端的 HTTP/2 配置参数。

Chrome 发送的 HTTP/2 SETTINGS 帧:

SETTINGS_HEADER_TABLE_SIZE: 65536
SETTINGS_ENABLE_PUSH: 0
SETTINGS_MAX_CONCURRENT_STREAMS: 1000
SETTINGS_INITIAL_WINDOW_SIZE: 6291456
SETTINGS_MAX_FRAME_SIZE: 16384
SETTINGS_MAX_HEADER_LIST_SIZE: 262144

而 curl 发送的 SETTINGS 帧:

SETTINGS_HEADER_TABLE_SIZE: 4096
SETTINGS_ENABLE_PUSH: 0
SETTINGS_MAX_CONCURRENT_STREAMS: 100
SETTINGS_INITIAL_WINDOW_SIZE: 65535

差异很明显:HEADER_TABLE_SIZE 从 65536 变成了 4096,INITIAL_WINDOW_SIZE 从 6291456 变成了 65535。每个参数的值都不一样。因为 HTTP/2 Settings 帧是第一个数据帧,它在 TCP 连接中的位置也是可预测的——检测系统可以通过测量 Settings 帧到达的时间来判断客户端是真实浏览器还是自动化工具。

TCP 时间戳与行为特征

除了应用层协议的特征,TCP 层面的细微差异也能用来判断:

TCP 时间戳选项:Linux 内核和 macOS 内核的 TCP 时间戳频率不同。Linux 的 TCP 时间戳每 1ms 增加一次,macOS 每 100ms 增加一次。如果服务器收到来自"Chrome on macOS"的请求,但 TCP 时间戳显示的是 Linux 的频率,这就是不一致的证据。

初始序列号(ISN)模式:不同的 TCP 实现使用不同的 ISN 生成算法。某些检测系统可以通过分析 ISN 的模式来推断客户端的操作系统。

窗口缩放因子:Chrome 默认请求的 Window Scale 值与其他工具有差异。

这些检测的意义

传输层检测和 JS 层检测的区别在于:JS 层的检测,自动化工具可以通过拉取最新的 stealth plugin 来绕过(至少暂时绕过)。传输层的检测,自动化工具改不了,因为这不是 JavaScript 能控制的范围。

举个例子:你用了 Camoufox,它在 C++ 引擎层修改了 Firefox 的所有指纹向量,能通过所有 JS 层的检测。但 Camoufox 的 TLS 握手是由底层的网络安全库(NSS)完成的,这个库的行为特征和 Chrome 的 BoringSSL 或者 curl 的 OpenSSL 是不一样的。如果目标网站的检测系统分析了你的 TLS 指纹,它仍然可以判断出你不是 Chrome。

实际中应对

传输层的检测比 JS 层的检测更难绕过。你可以做的事情不多,但下面几个方向值得尝试:

使用正确的网络栈。如果目标网站要求 Chrome,确保你的 TLS 栈特征和 Chrome 一致。某些反检测浏览器在这方面做了优化——它们替换了底层的 TLS 库来模拟 Chrome 的 BoringSSL 行为。

注意一致性。传输层特征和应用层特征必须相互印证。如果 TLS 握手显示"Chrome on Windows",但你的 User-Agent 显示"Chrome on macOS",这就是立即拦截的理由。

代理的传输层影响。使用代理会改变传输层的一些特征。隧道代理可以在一定程度上隐藏真实的 TLS 指纹,但住宅代理加 HTTP 代理会引入新的特征(例如代理附加的 HTTP 头)。在配置代理时需要注意这一点。

传输层检测不是每个网站都会用,它增加了检测系统的复杂度和计算成本。但随着反爬对抗的升级,越来越多的平台在接入这种检测方式。如果你负责维护高价值目标网站的采集通道,传输层检测是你迟早要面对的问题。

下一篇文章分析应用层的新检测向量:Canvas 已经是老黄历了,2026 年的应用层检测在看什么。

需要企业代理方案?

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