百趣云 百趣云的博客

TLS 指纹对抗:JA3 是怎么出卖你的爬虫的

JA3:TLS 握手的"指纹"

你的爬虫参数全对、ua 完美伪装,还是被 Cloudflare/Akamai 秒拒——问题出在 TLS 指纹。TLS 握手的第一条消息(ClientHello)里包含:

  • 支持的 TLS 版本列表
  • 加密套件(cipher suites)列表及顺序
  • 扩展(extensions)列表及顺序
  • 椭圆曲线、签名算法等参数

这些字段的组合由TLS 库的实现决定:Chrome 的 BoringSSL、Firefox 的 NSS、Python 的 OpenSSL、Go 的 crypto/tls,各有各的固定模式。JA3 就是把这些字段拼起来算 md5:

JA3 = md5(TLS版本,加密套件列表,扩展列表,椭圆曲线,椭圆曲线点格式)
Chrome 120: 771,4865-4866-4867-49195-...,0-23-65281-10-11-...,29-23-24,0
Python requests: 771,4866-4867-4865-...,0-11-10-...,...

服务端一看 JA3 就知道你是 Python 脚本还是真浏览器——ua 伪装得再好,TLS 层的指纹改不了(requests 用的 OpenSSL 配置和浏览器完全不同)。

检测自己的 JA3

# 在线服务查看自己的 TLS 指纹
curl https://tls.peet.ws/api/all   # 返回你的 JA3 和 HTTP/2 指纹

对比 Chrome 真实访问的结果,差异一目了然。

对抗方案一:curl_cffi(推荐)

curl_cffi 基于 curl-impersonate(编译时嵌入浏览器 TLS 配置的 libcurl),能逐字节复刻浏览器的 ClientHello:

from curl_cffi import requests

# impersonate 参数指定模拟的浏览器版本
resp = curl_cffi.requests.get(
    'https://target.com/api',
    impersonate='chrome120'   # 或 chrome116/safari15_3/edge99 等
)
# TLS 指纹与真实 Chrome 120 完全一致

支持的指纹列表随版本更新(chrome110/116/119/120/123+、safari15_3/17_0、edge 等)。选指纹时和 ua 匹配:ua 说 Chrome 120,impersonate 就用 chrome120。

对抗方案二:utls(Go 生态)

Go 的 uTLS 库提供同样的能力:

import tls "github.com/refraction-networking/utls"

conn, _ := tls.UClient(rawConn, &tls.Config{
    ServerName: "target.com",
}, tls.HelloChrome_120)   // 预置的浏览器指纹

对抗方案三:浏览器自动化兜底

Cloudflare 高强度防护(5 秒盾、Turnstile)下,TLS 指纹只是第一道——还有 JS 挑战、行为检测。这时协议模拟整体失效,上真实浏览器(Camoufox/undetected-chromedriver),TLS 指纹天然真实。

精髓:三个实战要点

  1. JA3 不是唯一指纹,HTTP/2 指纹同样致命。H2 的 SETTINGS 帧、窗口大小、优先级策略也是库特征(下篇详述)。curl_cffi 同时模拟了 H2 指纹,这是它比"只改 JA3 的库"强的地方
  2. 指纹和 IP 要匹配场景。数据中心 IP + 完美浏览器指纹,比住宅 IP + Python 指纹更可疑——风控看的是组合合理性。代理质量差时,指纹做得再好也白搭
  3. 指纹库要跟进浏览器版本。Chrome 每版本 TLS 指纹微调,用 chrome99 的指纹配 Chrome 120 的 ua 是低级错误。curl_cffi 定期更新,跟着升级

检测侧视角:风控怎么用 JA3

理解对手才能对抗。风控的典型策略:

  • JA3 黑名单:已知爬虫库(python-requests、Go-http-client、curl)的 JA3 直接拒
  • JA3 + ua 一致性:ua 是 Chrome 但 JA3 是 OpenSSL = 必假
  • JA3 白名单:只放行主流浏览器的 JA3 集合

curl_cffi 过的是"一致性"和"白名单"两关——这也是它成为当前爬虫标配的原因。

总结

  1. JA3 = TLS ClientHello 的字段组合指纹,暴露 TLS 库实现
  2. ua 伪装在 TLS 层无效,Python/Go 的默认指纹一眼假
  3. curl_cffi(Python)/ uTLS(Go)逐字节复刻浏览器指纹
  4. 指纹、ua、IP 三者要组合合理,单一完美没意义

交流微信:run1255

By 百趣云 阅读量:5 On