后量子密钥交换为 TLS ClientHello 增加新字段。了解 ML-KEM 和 ML-DSA 如何重塑 JA3/JA4 指纹,以及这对检测系统意味着什么。
2026 年,后量子密码学不再只是研究课题,而是开始出现在生产环境的 TLS 握手中。Cloudflare 最近撰文主张经典签名算法不能简单地等待更好的后量子替代方案,APNIC 也一直在追踪后量子密码在网络运营层面的实际落地情况。这两篇文章谈的都是部署问题,而非指纹识别——但它们描述的机制改变的,正是 JA3/JA4 指纹识别一直在读取的那个 ClientHello。本文要谈的正是这个副作用:后量子密钥交换和签名算法,究竟对你的 TLS 指纹做了什么。
核心要点
- 后量子密钥交换为 ClientHello 增加了一个新的支持组,而非新协议。 像
X25519MLKEM768这样的混合机制,位于 JA3/JA4 早已在哈希的同一批supported_groups和key_share扩展中。 - 密钥共享数据量大得多。 经典的 X25519 密钥共享只有 32 字节;混合 ML-KEM-768 的密钥共享则远超 1000 字节——有时足以让 ClientHello 跨越 UDP 或分片 TCP 的边界。
- ML-DSA 影响的是另一个扩展
signature_algorithms,用于握手签名而非密钥交换——是同一条消息中一次独立而互补的变化。 - 各浏览器和版本的支持程度并不一致,因此客户端是否提供 PQC 支持组、以及它出现在什么位置,构成了一个全新且当前高熵的指纹信号。
- JA4 已经能正确处理这一变化。 由于它在哈希前会按数值排序扩展和密码套件,客户端开启或关闭 PQC 支持只会改变参与哈希的排序值集合——不会像顺序敏感的 JA3 那样破坏格式。
ClientHello 里到底新增了什么
TLS 指纹识别之所以成立,是因为 ClientHello——密码套件、扩展、支持组、密钥共享——由 TLS 库决定,而非由用户决定。后量子密钥交换并没有增加新的消息类型或新的往返,它改变的是同一个 ClientHello 中已有两个字段的内容:
supported_groups新增了一个或多个用于混合密钥交换的命名组,最引人注目的是X25519MLKEM768——它结合了经典的 X25519 椭圆曲线 Diffie-Hellman 和基于格的密钥封装机制 ML-KEM-768(NIST 已将其标准化为 FIPS 203)。IETF 的 TLS 混合 ML-KEM 密钥交换草案精确规定了这在 TLS 1.3 中是如何协商的。key_share携带客户端愿意主动发送的各个组对应的实际密钥材料。这正是 PQC 留下最明显指纹的地方:仅 ML-KEM-768 的公钥就有 1184 字节,远超 X25519 的 32 字节,因此混合密钥共享比经典密钥共享大一个数量级以上。
签名则是另一回事。ML-DSA(模格数字签名算法,FIPS 204)出现在 signature_algorithms 扩展中,控制的是握手本身如何被认证——而非共享密钥如何派生。客户端或服务器可以支持后量子密钥交换、后量子签名、两者兼有,或者两者都不支持,每一种组合都是 ClientHello 中一种独特且可观察的模式。
为何是混合方案,而非纯后量子方案
如今 TLS 中每一个已部署的后量子组都是混合的:它将经典算法(X25519)与后量子算法(ML-KEM)结合,而不是直接取代 X25519。共享密钥由两者共同派生,因此攻击者必须同时攻破椭圆曲线难题和格难题才能还原它——这是一种对冲策略,防范 ML-KEM 这个相对年轻的标准可能存在尚未被发现的弱点。这种对冲思路,也正是 Cloudflare 那篇文章讨论 ML-DSA 的角度:后量子签名方案比密钥交换更新、经受的考验更少,因此等待一个假设中更优的方案是真实的代价,而不只是谨慎。
为何这是一个指纹信号
指纹识别服务器不需要任何新基础设施就能注意到 PQC——JA3 和 JA4 早已在哈希完整的 supported_groups 和扩展列表。变化的是这些哈希如今编码的内容:
版本与构建版本定位。 PQC 支持是逐步推出的——Chrome 在特定的发布区间默认启用了 X25519MLKEM768,其他浏览器则按各自的时间表跟进。一个提供或不提供该混合组的 ClientHello,结合 JA4 已读取的其他一切,不仅能缩小到"这是 Chrome",还能大致定位到具体是哪个 Chrome 版本。
为伪造客户端提供的一致性检查。 TLS 指纹识别已经在机器人检测中应用的同一套逻辑——握手是否与所声称的 User-Agent 应产生的结果相符——现在多了一个当前极具区分度的字段。一个尚未更新以添加 PQC 组的爬虫库或旧版 TLS 模拟工具,会与声称是当前浏览器版本的 User-Agent 产生不匹配,就像今天 Python requests 的握手与 Chrome User-Agent 不匹配一样。
大小本身,而不只是内容,现在也具有信息量。 由于 ML-KEM 密钥共享比经典密钥共享大得多,ClientHello 本身的原始大小就成为一个粗略信号——一个支持 PQC 的 ClientHello,在任何人解析具体字段之前就明显更大。
网络层的一个变数:更大的 ClientHello
更大的 key_share 扩展意味着更大的 ClientHello,这在 TLS 层之下会产生连锁影响。在 TCP 上,TLS 握手消息本就允许跨越多个 TCP 分段,因此更大的 ClientHello 大体上只意味着握手完成前多传输一点数据。在 QUIC 上,TLS ClientHello 搭载在 Initial 数据包中,一个大得多的 ClientHello 更可能需要客户端合并多个 UDP 数据报,或依赖连接的放大限制处理机制——这是一些中间设备和较旧的 QUIC 协议栈历史上处理得不太一致的边界情况。在符合规范的实现中,这些都不会破坏握手,但这又是一个 PQC 支持以可观察、依赖具体实现的行为形式呈现出来的地方,而不是一次不可见的内部改动。
这对检测系统意味着什么
这一切并没有带来新的检测类别——只是在已有类别里增加了一组新的取值。一个检查 TLS 指纹一致性的机器人检测或反欺诈系统,多了一个可以推理的维度:这个客户端的 PQC 态势,是否与它所声称的浏览器和版本应产生的结果相符?在同一会话的多个请求之间,这种态势是否保持一致?一个终止并重新建立自己 TLS 连接的VPN 或拦截代理,会携带其自身 TLS 库的 PQC 支持情况(有或没有),与原始客户端无关——这与今天已经暴露 TLS 终止代理的破绽如出一辙,只是多了一个字段可供比对。
从更广泛的浏览器指纹识别视角看,这是一个网络层信号,而非 JavaScript 可观察的信号——你无法从 navigator 属性中读取页面的 TLS ClientHello。它与 TLS 指纹识别、HTTP/3/QUIC 指纹识别并列,都是服务器在你的浏览器渲染任何内容之前就能看到的又一个信息片段。
常见问题
后量子 TLS 会让我的连接变慢吗?
影响很小,而且主要体现在握手上,而非持续的吞吐量。更大的密钥共享会增加少量一次性的握手带宽和计算量;对现代网络上的大多数连接而言,这基本不可察觉。它更重要的影响场景,是高度受限的网络,或对 ClientHello 分片较敏感的路径,正如上文所述。
我能通过禁用后量子密钥交换来降低指纹熵吗?
如果你的浏览器暴露了这个选项,你可以这么做,但这很可能让你更容易被识别,而不是更难。随着支持 PQC 的组在当前浏览器版本中成为标准配置,一个明显缺少它们的 ClientHello,看起来会像是过时的构建版本或被刻意修改过的客户端——这是拿一个指纹信号换取了另一个更可疑的信号。
ML-KEM 和 ML-DSA 是同一回事吗?
不是。ML-KEM(FIPS 203)是用于密钥交换的密钥封装机制——它作为像 X25519MLKEM768 这样的混合组的一部分,出现在 supported_groups/key_share 中。ML-DSA(FIPS 204)是用于认证握手的签名算法,出现在 signature_algorithms 中。两者都是后量子的、基于格的、由 NIST 标准化的算法,但它们解决的是不同的问题,出现在 ClientHello 的不同字段中。
这对 JA3 指纹和 JA4 指纹的影响一样吗?
不一样,比大多数协议变化的差异都更明显。JA3 按客户端发送的实际顺序对密码和扩展进行哈希,因此对某个库如何在现有组中排列新增的 PQC 组这一点非常敏感。JA4 会在哈希前对两者排序,因此对排序差异具有鲁棒性,只反映实际的取值集合——包括是否存在 PQC 组——这使它成为追踪这一转变更稳定的选择。关于 JA3 和 JA4 更全面的区别,参见 TLS 指纹识别详解。


