JA4 指纹解析:t13d1516h2 与 b0da82dd1658 的含义

b0da82dd1658 是 Chromium JA4 的第三段:使用旧版 ALPS 码位、恢复的 TLS 1.3 会话。本文教你解读 JA4 字符串的每一部分,并附上可复现的真实数值。

JA4 Fingerprint Decoded: What t13d1516h2 and b0da82dd1658 Mean
本文目录

JA4 指纹是根据 TLS ClientHello 计算出的三段式字符串 a_b_c。a 段是可读的元数据(协议、TLS 版本、SNI、密码套件与扩展的数量、ALPN),b 段是排序后密码套件列表的 12 位 SHA-256,c 段是排序后的扩展加上签名算法的 12 位 SHA-256。如果你是搜索 b0da82dd1658 来的:它是一个 c 段,属于 Chromium。具体来说,这是基于 Chromium 的客户端在恢复 TLS 1.3 会话、且仍使用旧版 ALPS 扩展码位时产生的值。本文其余部分会说明我们是怎么得出这一结论的,以及如何自己解读任意 JA4 字符串。

JA4 指纹如何构成:a_b_c 格式

FoxIO 发布的 JA4 官方技术规范把指纹定义为一个人类可读的前缀加两个截断哈希,用下划线连接。所有地方都忽略 GREASE 值,所有哈希都用小写。

段字符数编码内容可能的取值
a1传输方式t = 基于 TCP 的 TLS,q = QUIC,d = DTLS
a2最高 TLS 版本(若存在 supported_versions 则取自它,否则取 ClientHello 版本)13、12、11、10、s3、d2、00 = 未知……
a1是否带 SNId = 域名(发送了 SNI),i = 无 SNI(通常是直连裸 IP)
a2密码套件数量(不含 GREASE)00–99
a2扩展数量(不含 GREASE,含 SNI 和 ALPN)00–99
a2第一个 ALPN 值的首尾字符h2、h1(http/1.1)、h3、00 = 无 ALPN
b12密码套件以 4 位十六进制表示、排序、逗号连接后的 SHA-256没有时为 000000000000
c12扩展(排序,去掉 SNI 0000 和 ALPN 0010)+ _ + 按线上顺序排列的签名算法,取 SHA-256没有时为 000000000000

有两个细节容易让人犯错。第一,a 段中的扩展数量包含 SNI 和 ALPN,而 c 段的扩展哈希不包含它们,所以同一个客户端无论连接主机名还是 IP,c 段都相同。第二,签名算法按客户端发送的顺序参与哈希,不做排序,因此即使扩展完全相同,只要客户端调整了签名算法的偏好顺序,c 段就会变。

逐段解读 t13d1516h2_8daaf6152771_…

  • t:基于 TCP 的 TLS,而非 QUIC。
  • 13:客户端提供的最高版本是 TLS 1.3。
  • d:存在 SNI 扩展,说明客户端连接的是域名。
  • 15:去掉 GREASE 后有 15 个密码套件。
  • 16:去掉 GREASE 后有 16 个扩展,包含 SNI 和 ALPN。
  • h2:第一个 ALPN 值是 h2,即客户端优先使用 HTTP/2。
  • 8daaf6152771:下面这串排序后密码套件的哈希,用任何 SHA-256 工具都能复现:
printf '%s' "002f,0035,009c,009d,1301,1302,1303,c013,c014,c02b,c02c,c02f,c030,cca8,cca9" \
  | sha256sum | cut -c1-12
# 8daaf6152771

这份列表是三个 TLS 1.3 套件加上 Chrome 的十二个旧版 TLS 1.2 套件。从 FoxIO 的示例到无头 Chrome 148,我们检查过的每个 Chromium 构建都仍然产生 8daaf6152771。所以 b 段只能告诉你“这是 Chromium 系的 TLS 协议栈”,几乎看不出版本。版本差异体现在 c 段。

如果你仔细读规范,还有一个小问题:其算法摘要中给出的是 t13d1516h2_8daaf6152771_b186095e22b6,而其计算示例的哈希结果是 e5627efa2ab1。我们重新计算了该示例,得到的是 e5627efa2ab1,因此第一个字符串应视为示意。

b0da82dd1658 是什么意思

b0da82dd1658 是 Chromium JA4 的 c 段,它正是下面这个字符串的哈希:

0005,000a,000b,000d,0012,0017,001b,0023,0029,002b,002d,0033,4469,fe0d,ff01_0403,0804,0401,0503,0805,0501,0806,0601

你可以自己验证:

printf '%s' "0005,000a,000b,000d,0012,0017,001b,0023,0029,002b,002d,0033,4469,fe0d,ff01_0403,0804,0401,0503,0805,0501,0806,0601" \
  | sha256sum | cut -c1-12
# b0da82dd1658

列表中有三个扩展可以识别出客户端:

  • 0029(pre_shared_key)。这是 TLS 1.3 会话恢复,只有当客户端已持有与同一服务器先前连接所得的票据时才会出现。它由 RFC 8446 §4.2.11 定义。没有它时,同一浏览器的哈希是 02713d6af862。
  • 4469(ALPS,原始码位)。Application-Layer Protocol Settings 是 Chrome 的一个扩展。BoringSSL 在 2023 年 9 月为它新增了码位(0x44cd),当前的 Chrome 发送的是新码位。所以 4469 指向较旧的 Chromium 构建,或者模仿旧版的工具。
  • fe0d(Encrypted Client Hello)。Chrome 在普通连接上也会发送 GREASE 形式的 ECH 扩展。

FoxIO 自己的 ja4plus-mapping.csv 把 t13d1517h2_8daaf6152771_b0da82dd1658 和 t13i1516h2_8daaf6152771_b0da82dd1658 标为 “Chromium Browser”。前缀的计数也对得上:15 个参与哈希的扩展加上 SNI 和 ALPN,带 SNI(d)时为 17,不带时(i)为 16。这也揭示了网上反复出现的一个矛盾:像 t13d1516h2_8daaf6152771_b0da82dd1658 这样的字符串不可能来自单个真实的 ClientHello,因为在 SNI 和 ALPN 都存在的情况下,这 15 个参与哈希的扩展必然得出 17 的计数。

我们还直接复现了这个值。2026-10-03,curl_cffi 0.16.3 使用 impersonate="chrome131" 向 tls.peet.ws 发出的第一个请求为 t13d1516h2_8daaf6152771_02713d6af862。同一会话上的第二个请求恢复了 TLS 会话,结果是 t13d1517h2_8daaf6152771_b0da82dd1658。简言之,b0da82dd1658 意味着“Chromium 风格的 ClientHello、旧版 ALPS 码位、恢复的会话”。这涵盖了真实的旧版 Chrome、Edge、Brave 和 Opera 构建、嵌入式 Chromium,以及固定在码位切换前 Chrome 配置的模拟库。仅凭 JA4 无法区分它们。

参考表:各客户端的真实 JA4 值

下列数值只来自两个来源:FoxIO 公布的示例和映射文件,以及我们在 2026-10-03 对 tls.peet.ws 的抓取(已注明版本)。库的取值高度依赖其 TLS 后端和编译选项,因此库相关的行只能当作示例,而非通用常量。凡是我们无法验证的行都已剔除,包括我们自己抓取的真实 Firefox 和 Safari 数据。

客户端JA4来源
无头 Chrome 148(Linux),新连接t13d1516h2_8daaf6152771_d8a2da3f94cd我们的抓取,Playwright Chromium
同一浏览器,恢复会话t13d1517h2_8daaf6152771_b6f405a00624我们的抓取
Chromium,旧版 ALPS 码位,新连接 / 恢复会话t13d1516h2_8daaf6152771_02713d6af862 / t13d1517h2_8daaf6152771_b0da82dd1658FoxIO 映射 CSV;用 curl_cffi chrome131 复现
基于 QUIC 的 Chromeq13d0312h3_55b375c5d22e_178839b6cec1FoxIO README
Mozilla Firefox(未注明版本)t13d1715h2_5b57614c22b0_7121afd63204FoxIO 映射 CSV
Safari(未注明版本)t13d2014h2_a09f3c656075_14788d8d241bFoxIO 映射 CSV
curl 8.5.0 / OpenSSL 3.0.13(Ubuntu)t13d3112h2_e8f1e7e78f70_b26ce05bbdd6我们的抓取;在 tls.peet.ws、BrowserLeaks 和 Scrapfly 上完全一致
Python requests 2.31 / urllib3 2.0.7,OpenSSL 3.0.13t13d3112h1_e8f1e7e78f70_b26ce05bbdd6我们的抓取
Go 1.24.1 net/http(默认客户端)t13d1311h2_f57a46bbacb6_e7c285222651我们的抓取
curl_cffi 0.16.3,impersonate="chrome146"t13d1516h2_8daaf6152771_d8a2da3f94cd我们的抓取
curl_cffi 0.16.3,impersonate="firefox147"t13d1717h2_5b57614c22b0_3cbfd9057e0d我们的抓取
curl_cffi 0.16.3,impersonate="safari2601"t13d2013h2_a09f3c656075_7f0f34a4126d我们的抓取

比单独某一行更重要的是其中的规律:

  • c 段识别的往往是 TLS 库,而不是应用。同一 OpenSSL 3 构建上的 curl 和 Python 共享 b26ce05bbdd6。FoxIO 的映射文件中有一条 Python 记录,前缀不同但 c 段相同。FoxIO 文件中的 Go 客户端与我们抓取的 Go 1.24 共享 e7c285222651。
  • requests 显示为 h1。urllib3 2.x 在 ALPN 中只声明 http/1.1,因此服务器还没读任何请求头,a 段就已告诉它对面不是浏览器。
  • 普通库仅凭计数就很容易识别。31 个密码套件(OpenSSL 默认),或 13 个密码套件加 11 个扩展(Go),与当前所有 Chromium 构建发送的 15/16 模式毫无相似之处。
  • 会话恢复会改变每个浏览器的 c 段。在我们的 curl_cffi 抓取中,恢复会话时 Firefox 从 17 个扩展变为 18 个,Safari 从 13 个变为 14 个。只把新连接的值列入白名单的检测规则,会误伤真实的回访用户。

Chrome 这一行还会继续变化。curl_cffi 最新的 chrome150 配置新增了三个签名算法:0904、0905 和 0906。它们是 IETF 草案中的 ML-DSA 码位,会把 c 段变成 806a8c22fdea。我们无法在稳定版 Chrome 150 上确认这一点,因此请把它当作预览,而非参考值。

JA4 为什么要对密码套件和扩展排序

JA4 对密码套件和扩展排序,是因为 Chrome 会刻意随机化扩展顺序,对顺序敏感的指纹(JA3)因此不再稳定。Chrome 大约在 2023 年初的 Chrome 110 中上线了 TLS ClientHello 扩展置换,目的是防止服务器和中间设备依赖固定的布局。Fastly 测量了其影响:由于 JA3 按线上顺序对扩展做哈希,同一个 Chrome 安装几乎每次连接都会产生不同的 JA3。

JA4 的解决办法是先排序再哈希。FoxIO 于 2023 年 9 月将其作为 JA4+ 套件的一部分发布(APNIC 转载)。如今,Cloudflare Bot Management、AWS CloudFront 与 WAF、Google Cloud Armor、Fastly、Akamai,以及 FoxIO README 中列出的其他产品都提供 JA4。

这对爬虫来说有利有弊。随机化扩展顺序已经改变不了你的指纹,这招算是废了。真正起作用的是密码套件的集合、扩展的集合以及签名算法的顺序。实践中,这意味着要使用真实浏览器所用的 TLS 协议栈,或者能高度仿真的库。如果你需要原始顺序的视图(例如与 JA3 比较),规范定义了 JA4_o 以及原始变体 JA4_r / JA4_ro。BrowserLeaks 会返回全部四种。关于 JA3 的更多内容,请参阅我们的 TLS 指纹识别解析。

JA4+ 家族:JA4S、JA4H、JA4X、JA4T

JA4 只是更大套件中的一种方法。其他方法分别关注服务器、HTTP 层、证书和 TCP,而且采用不同的许可证。

方法识别对象格式概要
JA4S服务器的 ServerHello协议 + 版本 + 扩展数量 + ALPN,然后是选定的密码套件,再是服务器扩展的哈希
JA4HHTTP 请求方法(ge、po……)、版本(11、20)、cookie c/n、referer r/n、请求头数量、Accept-Language 前 4 个字符;然后是按顺序排列的请求头名称、排序后的 cookie 名称、排序后的 cookie 名=值对各自的哈希
JA4XX.509 证书颁发者 RDN OID、主体 RDN OID 和扩展 OID 的哈希(反映证书如何构建,而不是其取值)
JA4TTCP SYN窗口大小、按顺序排列的 TCP 选项、MSS、窗口缩放,例如 Windows 11 为 64240_2-1-3-1-1-4_1460_8

上述格式取自 FoxIO 的技术细节示意图和参考 Python 实现。对爬虫影响最大的是 JA4H。它的 b 段按发送顺序对请求头名称做哈希,所以即使每个值都正确,只要客户端发送 Chrome 请求头的顺序不对,就会被看出来。相关的 SETTINGS 和伪头部顺序信号,请参阅我们的 HTTP/2 指纹识别文章。JA4T 会暴露操作系统:无论 User-Agent 怎么写,Linux 服务器的 SYN 都不会像 Windows。

许可证

根据代码仓库的许可证说明,JA4(TLS 客户端指纹)与 JA3 一样采用 BSD 3-Clause 许可,FoxIO 表示对其不主张任何专利权。JA4S、JA4L、JA4LS、JA4H、JA4X、JA4SSH、JA4T、JA4TS、JA4TScan、JA4D、JA4D6 以及其他 “JA4+” 方法正在申请专利,采用 FoxIO License 1.1 许可。该许可允许内部使用和学术用途,但若厂商把 JA4+ 指纹识别作为产品的一部分出售,则需要 OEM 许可。

QUIC 与 HTTP/3:q 前缀说明了什么

以 q 开头的 JA4 是根据 QUIC Initial 数据包计算的,意味着客户端正在建立 HTTP/3 连接。QUIC 在其 CRYPTO 帧中携带 TLS 1.3 ClientHello。Initial 数据包的保护密钥由客户端选定的 Destination Connection ID 派生(RFC 9001 §5.2),因此任何链路上的观察者或边缘服务器都能解密它,并像在 TCP 上一样精确地识别 ClientHello 指纹。

Chrome 的 QUIC 指纹与其 TCP 指纹截然不同:FoxIO 示例中为 q13d0312h3_55b375c5d22e_178839b6cec1。也就是 3 个密码套件(仅 TLS 1.3,因为 QUIC 禁止旧版本)和 ALPN h3。这对自动化很重要,因为一旦站点声明支持 HTTP/3,浏览器就会切换过去,而大多数 HTTP 客户端从不切换。Cloudflare 文档中的 JA4 Signals 包含一个 h2h3_ratio_1h 值:某个 JA4 的流量中,经 HTTP/2 与经 HTTP/3 到达的比例。在支持 HTTP/3 的站点上从不通过 QUIC 出现的“Chrome” TLS 指纹,就是一个统计离群点。curl_cffi 的 README 称,自 v0.15.0 起已支持 HTTP/3 指纹模拟。

如何查看自己的 JA4

最快的检查方式是使用回显服务,它读取你的 ClientHello 并返回指纹。下面三个服务在我们的测试中都返回了 JA4,而且结果逐字节一致:

curl -s https://tls.peet.ws/api/all | python3 -c \
  "import sys, json; d = json.load(sys.stdin); print(d['http_version'], d['tls']['ja4'])"

同样的检查要通过你的代理再跑一遍,而不仅是在你的笔记本上跑。用 CONNECT 建立隧道的正向代理会原样传递你的 ClientHello,但拦截 TLS 的代理、企业中间设备或某些 SDK 层会换成它们自己的。例如,使用 ProxyHat 住宅出口:

curl -s -x http://USERNAME:PASSWORD@gate.proxyhat.com:8080 https://tls.peet.ws/api/all

Wireshark 与 tshark

Wireshark 自 4.2.0 起原生计算 JA4,显示过滤字段为 tls.handshake.ja4(以及 tls.handshake.ja4_r),详见 TLS 字段参考。FoxIO 的 JA4+ 插件(需 Wireshark 4.4.0 或更高版本)在 ja4.* 下补充了套件中的其余方法,例如 ja4.ja4s、ja4.ja4h 和 ja4.ja4t。从抓包文件中提取指纹:

tshark -r capture.pcapng -Y "tls.handshake.ja4" -T fields \
  -e ip.dst -e tls.handshake.extensions_server_name -e tls.handshake.ja4

请在你能控制客户端的机器上抓包。要识别无头浏览器发出的 HTTPS 流量指纹,就在本地运行它,并在回环接口或出站接口上抓包。ClientHello 是未加密的,所以计算 JA4 不需要 TLS 密钥。但对 HTTPS 计算 JA4H 则需要。

实际意义:请求头必须与握手匹配

修改 User-Agent 不会改变你的 JA4。一个发送 Chrome User-Agent 的 Python 脚本,在任何请求头被读取之前,握手中呈现的仍然是 t13d3112h1_e8f1e7e78f70_b26ce05bbdd6。这种不匹配(自称 Chrome,协商方式却像 OpenSSL,还请求 HTTP/1.1)是边缘节点能做的最廉价的检查之一,也正是 JA4 数据库要捕捉的对象。

主流的解决办法有两种,都各有局限。

  • curl_cffi(curl-impersonate 的 Python 绑定)会按指定的浏览器配置构造 ClientHello 和 HTTP/2 帧:requests.get(url, impersonate="chrome")。在我们的抓取中,它当前的 Chrome 配置产生的 JA4 与真实的无头 Chrome 148 相同。会话与代理的用法见我们的 curl_cffi 指南。
  • Go 的 uTLS 用 “parrot”(如 tls.HelloChrome_Auto)替换 crypto/tls 的 ClientHello,用法是 tls.UClient(conn, &config, helloID)。它的 README 明确指出,模仿可能并不完美,而且不涉及 ClientHello 之外的部分。我们的 Go uTLS 教程演示了如何把它接入 net/http。

模拟解决不了的问题

JA4 匹配只能让你通过第一道筛选。

  • JA4 必须与声称的浏览器版本一致:Chrome 148 的 User-Agent 配上码位切换前的 ALPS(b0da82dd1658),本身就是一处小小的不匹配。
  • JA4H 的请求头顺序也必须匹配。
  • JA4T 和 IP 数据会暴露主机的操作系统和网络。
  • JavaScript 挑战在 HTTP 客户端中根本不会执行。
  • 行为(请求频率、浏览模式)会被单独评判。

选择与你发送的 User-Agent 相符的配置,保持会话存活,让会话恢复看起来正常,并让出口 IP 与流量相称。住宅出口解决的是网络信誉层,而不是 TLS 层。请按上文所示通过代理检查指纹。

最后,理解指纹的意义在于让正当的自动化行为诚实、可预期,而不是去突破一个已经决定拒绝自动化访问的网站。在适用的情况下请遵守 robots.txt 和服务条款,并记住,采集个人数据会带来法律义务,再完美的 JA4 也无法替你免除。

常见问题

JA4 指纹里的 b0da82dd1658 是什么?

它是 JA4 的第三段(c 段):排序后的扩展列表加签名算法的截断 SHA-256。它对应一个包含 pre_shared_key(恢复的 TLS 1.3 会话)和原始 ALPS 码位 0x4469 的 Chromium 风格 ClientHello。FoxIO 的映射文件把 t13d1517h2_8daaf6152771_b0da82dd1658 标为 Chromium Browser。

JA4 中的 t13d1516h2 是什么意思?

t 表示基于 TCP 的 TLS,13 表示 TLS 1.3,d 表示发送了 SNI 主机名,15 是密码套件数量,16 是扩展数量(不含 GREASE,含 SNI 和 ALPN),h2 是第一个 ALPN 值的首尾字符,即 HTTP/2。

JA3 和 JA4 有什么区别?

JA3 是对 ClientHello 各字段按线上顺序计算的一个 MD5 哈希,因此 Chrome 的扩展顺序随机化让它几乎每次连接都产生新的 JA3。JA4 在哈希前对密码套件和扩展排序,把结果拆成一个可读前缀和两个哈希,并且覆盖 QUIC。JA4 与 JA3 一样采用 BSD 许可;更广泛的 JA4+ 套件则采用 FoxIO License。

怎么查看自己的 JA4 指纹?

从要测试的客户端请求 tls.peet.ws/api/all、tls.browserleaks.com/json 或 Scrapfly 的 JA3/JA4 工具,它们都会返回看到的 JA4。如果是抓包,Wireshark 4.2+ 提供 tls.handshake.ja4 字段,可以用 tshark 的 -T fields 打印出来。

改 User-Agent 会改变 JA4 吗?

不会。JA4 根据 TLS ClientHello 计算,而 ClientHello 在任何 HTTP 请求头之前发送。带 Chrome User-Agent 的 Python 或 Go 客户端呈现的仍是其自身库的 JA4,服务器很容易发现这种不匹配。只有换用不同的 TLS 协议栈(如 curl_cffi 或 uTLS)才能改变它。

准备好开始了吗?

覆盖 195+ 国家的住宅、ISP 和移动代理。创建免费账户。

创建免费账户
← 返回博客