
一、为什么 UA 和 IP 越来越不可靠
传统 WAF 识别爬虫,主要看 User-Agent 和源 IP。但这两个字段都太容易伪造了:UA 是纯文本,改一行代码就能伪装成 Chrome;IP 有大量代理池、秒拨 IP 可供切换。结果是爬虫换个 UA、换个 IP,就又能畅通无阻。
于是安全厂商把目光投向了更底层的位置——TLS 握手。无论你怎么改 UA,浏览器发起的 TLS 握手包结构和 Python requests 发出来的,就是不一样。这个差异,就是 JA3 指纹的立足点。
二、JA3 指纹是怎么算出来的
JA3 由 Salesforce 团队在 2017 年提出,核心思路是:在 TLS ClientHello 报文中抽取 5 个关键字段,拼接成字符串后取 MD5。具体字段如下:
| 抽取字段 | 内容说明 |
|---|---|
| TLS Version | TLS 协议版本号,如 771(TLS 1.2) |
| Cipher Suites | 客户端支持的加密套件列表及顺序 |
| Extensions | 扩展字段类型列表(去 SNI) |
| Elliptic Curves | 支持的椭圆曲线列表 |
| EC Point Formats | 椭圆曲线点格式 |
把这 5 项按固定格式用逗号拼接,再用 MD5 计算,就得到一个 32 位十六进制字符串,这就是 JA3 指纹。同一个版本的 Chrome,JA3 指纹是稳定的;不同工具(curl、Go、Java)各有各的指纹。
# JA3 拼接格式(示意)
771,4865-4866-4867-49195-49199,0-11-10-35-16-5-13-18-51-45-43-27-17513,29-23-24,0
# MD5 后得到 JA3 指纹
a0e9f5d64349fb13191bc781f81f42e1
三、WAF 如何利用 JA3 做防护
3.1 建立指纹信誉库
WAF 厂商会持续收集公开的爬虫工具、扫描器、攻击平台的 JA3 指纹,形成一个”恶意指纹库”。当客户端握手时,WAF 提取 JA3 并比对库中记录,命中即拦截或强制人机验证。
3.2 设置业务指纹白名单
反过来也可以做白名单。比如你的 App 用的是固定版本 OkHttp,JA3 是稳定的,可以把它加入白名单,实现”只放行自家客户端”,把第三方的脚本采集全部挡在门外。
3.3 与其它维度联动
- JA3 异常 + 请求频率高 → 判定为爬虫,直接拦截
- JA3 为浏览器但 UA 不匹配 → 判定为伪装,触发验证码
- 同一 JA3 对应大量不同 IP → 判定为代理池,加入限速
- JA3 为已知扫描器 → 记录并封禁,无需看内容
四、配置示例:Nginx 侧记录 JA3
如果你的源站是 Nginx,可以借助第三方模块在日志中记录 JA3,便于事后溯源分析:
log_format ja3log '$remote_addr - [$time_local] "'$request'" '
'ja3=$http_ssl_ja3 ja3_hash=$http_ssl_ja3_hash';
server {
listen 443 ssl;
access_log /www/wwwlogs/ja3.log ja3log;
}
注意:原生 Nginx 不直接支持 JA3,需要编译 ngx_http_ssl_ja3 模块,或在前面挂一层支持 JA3 的 WAF/CDN。对绝大多数站长而言,直接用云 WAF 开启 TLS 指纹功能,成本更低。
五、JA3 的局限与应对
- 指纹会变:浏览器版本升级、TLS 库更新都会改变 JA3,需持续更新库
- 可被模拟:高级爬虫可以用 uTLS 等库伪造 JA3,但成本很高,能挡住 90% 以上的低门槛采集
- 加密流量干扰:ECDHE 密钥交换本身不加密 ClientHello,JA3 可用;但 ECH 普及后需依赖 JA4
一句话总结:JA3 让”改 UA 换 IP”的老套路失效,是当前最有效的爬虫识别手段之一。
六、小结
JA3 指纹把识别维度从”应用层文本”下沉到”传输层结构”,从根上解决了 UA/IP 易伪造的问题。对于有内容防抓取、接口防滥用需求的站点,开启 TLS 指纹识别几乎是性价比最高的一步。
