curl-impersonate JA3 指纹原理与复现
curl-impersonate JA3 指纹原理与复现
前言
本文通过实际抓包验证,深入分析 curl-impersonate 的 TLS 指纹生成机制,并完整复现了 curl_chrome110 的 JA3 哈希计算全过程。
环境说明:curl-impersonate 安装于
/root/PycharmProjects/python-api/curl-impersonate/
一、curl-impersonate 核心原理
curl-impersonate 是一个魔改版 curl,在标准 curl 基础上添加了一系列自定义 flag 来模拟特定浏览器的 TLS 和 HTTP 指纹。
1.1 TLS 指纹层级
1 | |
1.2 curl_chrome110 完整配置
1 | |
1.3 关键 Flag 解析
| Flag | 作用 |
|---|---|
--ciphers |
TLS 加密套件列表,决定 JA3 哈希 |
--cert-compression brotli |
证书压缩算法(Chrome 特有) |
--false-start |
TLS False Start(Chrome 性能优化) |
--alps |
ALPS 扩展(HTTP/2 早期加密,Chrome 私有) |
--tls-permute-extensions |
打乱 TLS 扩展顺序(BoringSSL 特性) |
--http2-no-server-push |
禁用 HTTP/2 Server Push |
二、JA3 哈希算法详解
2.1 JA3 生成公式
1 | |
2.2 TLS 版本字段
| TLS 版本 | Hex 值 | JA3 中表示 |
|---|---|---|
| TLS 1.0 | 0x0301 | 769 |
| TLS 1.1 | 0x0302 | 770 |
| TLS 1.2 | 0x0303 | 771 |
| TLS 1.3 | 0x0304 | 772 |
Chrome 110 使用 TLS 1.2,所以版本字段为 771。
2.3 Cipher Suites(15个)
| 序号 | IANA 名称 | Hex 值 |
|---|---|---|
| 1 | TLS_AES_128_GCM_SHA256 | 1301 |
| 2 | TLS_AES_256_GCM_SHA384 | 1302 |
| 3 | TLS_CHACHA20_POLY1305_SHA256 | 1303 |
| 4 | ECDHE-ECDSA-AES128-GCM-SHA256 | c02c |
| 5 | ECDHE-RSA-AES128-GCM-SHA256 | c02f |
| 6 | ECDHE-ECDSA-AES256-GCM-SHA384 | c024 |
| 7 | ECDHE-RSA-AES256-GCM-SHA384 | c02b |
| 8 | ECDHE-ECDSA-CHACHA20-POLY1305 | cca9 |
| 9 | ECDHE-RSA-CHACHA20-POLY1305 | cca8 |
| 10 | ECDHE-RSA-AES128-SHA | c013 |
| 11 | ECDHE-RSA-AES256-SHA | c014 |
| 12 | AES128-GCM-SHA256 | 009c |
| 13 | AES256-GCM-SHA384 | 009d |
| 14 | AES128-SHA | 002f |
| 15 | AES256-SHA | 0035 |
2.4 TLS Extensions(16个,真实顺序)
Chrome 110 在 ClientHello 中发送的扩展顺序:
| ID | 名称 | 说明 |
|---|---|---|
| 23 | ALPN | 应用层协议协商 |
| 13 | supported_versions | TLS 1.3 版本支持 |
| 51 | key_share | TLS 1.3 密钥共享 |
| 5 | status_request | OCSP 证书状态请求 |
| 65281 | 0xff01 | GREASE(Chrome 随机插入) |
| 0 | server_name | SNI 主机名 |
| 27 | compress_certificate | 证书压缩 |
| 43 | supported_versions | TLS 1.2 客户端版本 |
| 16 | encrypt_then_mac | 加密后 MAC |
| 10 | supported_signature_algorithms | 支持的签名算法 |
| 45 | psk_exchange_modes | PSK 交换模式 |
| 17513 | 0x4469 | GREASE |
| 18 | signed_certificate_timestamp | SCT 时间戳 |
| 35 | session_ticket | 会话票据 |
| 11 | use_srtp | SRTP 媒体加密 |
| 21 | padding | 填充 |
2.5 椭圆曲线
| ID | 名称 |
|---|---|
| 29 | X25519 |
| 23 | secp256r1 |
| 24 | secp384r1 |
三、实际验证
3.1 抓取真实 TLS 指纹
使用 curl_chrome110 访问 Browserleaks:
1 | |
返回结果:
1 | |
3.2 JA3 与 JA3n 的区别
| 特性 | JA3 | JA3n |
|---|---|---|
| Extension 顺序 | ClientHello 真实顺序 | 按 ID 从小到大排序 |
| 用途 | 追踪特定浏览器配置 | 简化版指纹匹配 |
1 | |
3.3 Chrome 109+ GREASE 随机化
Chrome 109 (2022年1月) 引入重大变化:GREASE 值从固定改为随机。
Chrome 109 之前的 GREASE
Chrome 在 ClientHello 中插入固定的 GREASE 扩展值,JA3 指纹是稳定的:
1 | |
Chrome 109 之后的 GREASE
每次连接 GREASE 值从池中随机选择,导致同一个版本的浏览器每次请求 JA3 都不同:
1 | |
GREASE 值池(Chrome 定义的保留值):
| GREASE 值 | 用途 |
|---|---|
| 0x0a0a | Application Settings |
| 0x1a1a | Reserved (GREASE) |
| 0x2a2a | Reserved (GREASE) |
| 0x3a3a | Reserved (GREASE) |
| … | … |
| 0xFAFA | Reserved (GREASE) |
实际影响
| 对比 | Chrome 109 之前 | Chrome 109 之后 |
|---|---|---|
| JA3 稳定性 | 固定,可用于识别 | 每次不同,指纹库匹配失效 |
| JA3 Hash 数量 | 1个/浏览器版本 | N个/浏览器版本 |
| 反爬策略 | 匹配 JA3 Hash | 需要 JA3n 或多维度指纹 |
这就是为什么 curl-impersonate 的 curl_chrome110 在 Section 3.1 的返回中,JA3n(扩展排序后)是稳定的,而 JA3 依赖 GREASE 注入来模拟随机化。
3.4 JA4 哈希格式
JA4 是 2022 年发布的升级版指纹标准,比 JA3 更易读,且不受 GREASE 随机化影响:
1 | |
JA4 各字段含义(以 t13d1516h2_8daaf6152771_e5627efa2ab1 为例):
| 字段 | 位置 | 含义 | 示例值 |
|---|---|---|---|
p |
1字符 | 传输协议 | t=TLS over TCP, q=QUIC, d=DTLS |
v |
2字符 | TLS 版本 | 13=1.3, 12=1.2, 10=1.0 |
s |
1字符 | SNI 有无 | d=有域名, i=无 SNI |
c |
2字符 | 密码套件数量 | 15=15个 |
e |
2字符 | 扩展数量 | 16=16个 |
a |
2字符 | ALPN 首尾字符 | h2=http/2, h3=http/3 |
_ |
分隔符 | - | - |
b |
12字符 | 密码套件列表的 SHA256 前12位 | 8daaf6152771 |
_ |
分隔符 | - | - |
d |
12字符 | 扩展列表+签名算法的 SHA256 前12位 | e5627efa2ab1 |
b 字段计算示例(15个密码套件按十六进制排序后哈希):
1 | |
c 字段计算示例(扩展按十六进制排序、去 SNI/ALPN 后再加签名算法哈希):
1 | |
关键设计:GREASE 值在计算 b 和 c 字段时会被忽略(不参与排序和哈希),因此 Chrome 109+ 的 GREASE 随机化对 JA4 没有影响,这是 JA4 优于 JA3 的核心原因。
JA4 的设计目标:
- 人类可读 — 不需要解码十六进制
- GREASE 免疫 — 不受 Chrome 109+ 随机 GREASE 影响
- 可组合 — 各字段独立,可做细粒度匹配
- 协议无关 — 支持 TLS、QUIC、HTTP/2、HTTP/3
四、Python 复现代码
1 | |
五、相关工具与仓库
5.1 核心工具
| 仓库 | Stars | 说明 |
|---|---|---|
| lexiforest/curl_cffi | 5373 | Python 版 curl-impersonate,推荐使用 |
| salesforce/ja3 | 3085 | 原始 JA3 规范与实现 |
| FoxIO-LLC/ja4 | 1851 | JA4 升级版指纹 |
5.2 curl_cffi 使用示例
1 | |
5.3 指纹查询网站
- https://browserleaks.com/ja3 - 在线 JA3/JA4 检测
- https://ja3er.com - JA3 哈希数据库
六、总结
- JA3 哈希 = TLS ClientHello 的指纹,由 cipher 套件、扩展列表、椭圆曲线等字段计算得出
- Chrome 109 之前:同一浏览器版本的 JA3 固定,全球一致
- Chrome 109 之后:GREASE 值随机化,同一版本每次请求 JA3 都不同,JA3 Hash 匹配失效
- JA3n 是 JA3 的排序版本,将扩展按 ID 排序后计算哈希,更稳定
- JA4 是升级版指纹,人类可读、不受 GREASE 影响、支持多协议
- curl-impersonate 预置脚本已覆盖主流浏览器版本,直接使用即可复现真实浏览器指纹
- Python 推荐用 curl_cffi,比 bash 脚本更易于集成到项目