后量子 SSH 与 TLS
密钥协商已经解决并默认启用,签名还没有。一份在真实基础设施上排查并修复 SSH 与 TLS 的实操指南。
- 后量子
- SSH
- TLS
- 安全
后量子密码在学术会议上被讨论了十年,然后悄无声息地成了你笔记本上的默认值。如果你在用 OpenSSH 10 和近两年发布的浏览器,你的大部分流量其实已经能抵抗量子攻击者了,只是没人通知你。剩下要做的事范围很窄、不起眼,但非常具体:把落下的那些连接找出来。这篇文章讲的就是在真实基础设施上怎么做——查什么、改什么、改完怎么验证,以及哪一部分现在应该刻意先不动。

让这件事变得可处理的,是一个区分。密码学从两个方向保护连接:密钥协商决定加密会话的那个秘密,签名证明你在和谁通信。量子计算机把两者都能打破。但今天只有一个是紧急的,而把两者混为一谈,正是大量后量子项目最后卡在一张表格里的原因。下面所有内容都从这个区分推出来。
2026 年后量子密码的真实进度
密钥协商已经做完了。不是在规划,也不是在试点,而是已发布、已设为默认、正在跑。OpenSSH 从 2022 年 4 月的 9.0 版起就提供后量子密钥协商,而自 2025 年 4 月的 OpenSSH 10.0 起,混合算法 mlkem768x25519-sha256 已是默认算法。前一天发布的 OpenSSL 3.5.0 修改了默认的 TLS 支持组列表,把混合后量子组包含进去并优先,同时以 X25519MLKEM768 作为默认 keyshare。过去一年里更新过其中任何一个软件包的人,什么都没做就把它打开了。[ssh100][ossl35]
| 层次 | 2026 年现状 | 对你意味着什么 |
|---|---|---|
| SSH 密钥协商 | 自 OpenSSH 10.0(2025 年 4 月)起为默认;自 9.0(2022)起可用 | 升级软件包并确认协商出的算法。没有别的工作。 |
| TLS 密钥协商 | OpenSSL 3.5.0(2025 年 4 月)起默认优先混合组 | 先查二进制实际链接的 OpenSSL 版本,然后每个终结点一行配置。 |
| 对称加密 | AES-256 与 ChaCha20 被认为足够 | 无需处理。Grover 算法只是把有效密钥长度减半,仅此而已。 |
| 哈希 | SHA-256 及以上被认为足够 | 无需处理;淘汰 SHA-1 的理由比量子计算还早。 |
| 签名与 PKI | 已标准化(ML-DSA、SLH-DSA),但无法部署到公网 | 不要迁移。把签发自动化,以便条件成熟时能立刻行动。 |
测量数据也支持这个判断。Cloudflare 从 2023 年起持续发布后量子密钥协商的采用率,这条曲线在两年左右的时间里从一个舍入误差涨到了人类网页流量的多数。请去查实时数字,而不要相信任何一篇文章,包括这一篇——重点不是精确的百分比,而是曲线的形状:它告诉你落后者现在是一个有限的、可以逐个列举的集合,而不再是整个互联网。[cfpq][cfradar]
签名则完全相反。NIST 在 2024 年标准化了 ML-DSA 与 SLH-DSA,实现也有了,但没有一样能部署到公网上,因为证书只有在验证方已经信任签发它的根时才有意义——而浏览器信任库里没有任何后量子根证书。这不是一个可以靠工程手段绕过的临时打包问题,而是生态的先后次序问题,要用年来计。
先窃取、后解密——以及这个攻击不覆盖的部分
密钥协商紧急而签名不紧急,原因归结为一个不对称,OpenSSH 把它说得比多数厂商材料都清楚:[pq]
一条 SSH 连接的全部私密性都取决于密码学密钥协商。如果攻击者能攻破密钥协商,他就能解密并查看整个会话。他不需要实时发动这次攻击:他可以现在收集加密的 SSH 会话,等日后拿到量子计算机再解密。[pq]
这就是先窃取、后解密,一种可以回溯的攻击。今天在链路上被抓走、用经典密钥交换保护的会话,是一笔永久负债:它躺在归档里,直到具备密码学意义的量子计算机出现,然后就被打开了。你在 2032 年做的任何事,都救不回 2026 年被录下的那次会话。签名没有对应的问题,因为事后伪造签名并不能让你回到已经结束的对话里去冒充谁。由此得到一条干净的优先级规则:
- 长生命周期机密数据走在长生命周期链路上。跨广域网的数据库复制、备份传输、站点间 VPN 隧道、你会在里面粘贴凭据的 SSH 会话。先修这些:这些载荷十年甚至更久之后仍然有价值。
- 穿越不可信路径的流量。所有离开你自己网络的东西;在严肃的威胁模型里,还包括穿过云厂商骨干网的东西。对有位置优势的对手来说,抓包很便宜,存储更便宜。
- 无人登录的机器对机器链路。这些恰恰是审计会漏掉的,因为没有人能看到告警。服务网格、消息队列、复制通道、监控代理。
- 短生命周期、低价值、纯内部的流量。同一节点上两个 Pod 之间的健康检查,不值得开一张迁移工单。把这句话写下来,让例外成为一个决定,而不是一次疏忽。
关于具备密码学意义的量子计算机何时出现,估计从五年到二十年不等,不少观察者押在 2030 年代中期。你不需要对这个数字有立场。你需要知道的是:你今天传输的数据,在那个时间点是否仍然敏感——对大多数基础设施来说,诚实的答案是「是」。[pq]
修好 SSH
SSH 是最容易拿下的一仗,也是正确的起点,因为难的部分 OpenSSH 已经替你做完了。没有插件,没有要装的 provider,没有实验分支。只有一个版本号和一行配置,而且两者项目方都有公开文档。[ssh100][pq][ssh105][sshrel]
| OpenSSH 版本 | 后量子密钥协商 | 该做什么 |
|---|---|---|
| 10.0 及以上(2025 年 4 月起) | 默认 mlkem768x25519-sha256 | 无需操作,但要验证——本地的 KexAlgorithms 覆盖仍可能把它关掉。 |
| 9.9 | mlkem768x25519-sha256 已存在,但还不是首选 | 在 KexAlgorithms 里把它放到最前,或者升级。这里两种算法名都可用。 |
| 9.0 – 9.8 | 默认 sntrup761x25519-sha512 | 今天就是抗量子的,但只能用 sntrup761x25519-sha512@openssh.com 这个名字;短名称和 ML-KEM 都是 9.9 才有的。 |
| 8.5 – 8.9 | 有 sntrup761x25519-sha512@openssh.com,但从不被优先选中 | 最微妙的一档:在 8.9 上它位于默认列表中,却排在经典曲线之后,所以它被提供、却永远不会被选中。要显式把它放到最前。 |
| 低于 8.5 | 没有 | 真正的暴露面在这里。升级,或者带日期地记录已接受的风险。 |
这张表里藏着两个坑。第一个是名字:短名称 sntrup761x25519-sha512 从 9.9 才有,更早的版本必须写 @openssh.com 那一种,而 sshd 遇到不认识的名字会拒绝启动。第二个更隐蔽:出现在默认列表里,和被从列表中选中,是两回事。在 OpenSSH 8.9 上,后量子算法确实包含在默认的 KexAlgorithms 里,但排在第六位,位于 curve25519-sha256 之后——于是任何现代客户端与它协商出来的都是经典交换,而服务器却如实地报告自己「支持后量子」。这正是本文反复强调要读协商结果、而不是读支持列表的原因。[ssh85][ssh99][ntru]
第一步:查清你实际协商的是什么
改任何东西之前,先测量。绊住大多数人的区分是支持与协商:服务器可以支持 ML-KEM,却仍然完成一次经典交换,因为某个老客户端提出了请求,而服务器的偏好列表允许了它。只有协商出来的算法,才能告诉你某条具体连接是否真的受到了保护。
# 1. Your client. Anything older than 8.5 has no post-quantum key agreement
# at all; 8.5 through 9.8 have it only under the @openssh.com vendor name.
ssh -V
# OpenSSH_10.5p1, OpenSSL 3.5.7 9 Jun 2026
# 2. The remote server's software version, straight from the protocol banner.
ssh -v server.example.com exit 2>&1 | grep 'remote software version'
# debug1: Remote protocol version 2.0, remote software version OpenSSH_10.3
# 3. Which key agreement algorithms your local build even supports.
ssh -Q kex | grep -E 'mlkem|sntrup'
# mlkem768x25519-sha256
# sntrup761x25519-sha512
# 4. Supported is not preferred. On OpenSSH 8.9, for example, the PQ algorithm
# is in the default list but sixth in it, so it is offered and never chosen:
ssh -G server.example.com | grep -i '^kexalgorithms'
# kexalgorithms curve25519-sha256,curve25519-sha256@libssh.org,ecdh-sha2-nistp256,
# ecdh-sha2-nistp384,ecdh-sha2-nistp521,sntrup761x25519-sha512@openssh.com,...
# ^ present, but nothing will ever pick it
# 5. The only answer that matters: what did THIS connection actually agree on?
# Everything above is capability; this line is the negotiated result.
ssh -v server.example.com exit 2>&1 | sed -n 's/.*kex: algorithm: /negotiated: /p'
# negotiated: mlkem768x25519-sha256只要你会读一台主机上的那一行,你就会读所有主机上的。OpenSSH 10.1 在客户端加了一个告警:当连接协商出非后量子交换时会提示。这对人很好用,对构成真实机群主体的自动化链路则毫无用处。所以自己扫一遍:[ssh101]
#!/usr/bin/env bash
# pq-ssh-sweep.sh - classify every host in hosts.txt by negotiated key agreement.
# Read-only: it opens a connection, runs `exit`, and reads the debug output.
set -uo pipefail
while read -r host; do
[ -z "$host" ] && continue
# </dev/null matters: without it ssh swallows the rest of hosts.txt from the
# loop's stdin and you silently audit only the first host.
alg=$(ssh -o BatchMode=yes -o ConnectTimeout=5 -o StrictHostKeyChecking=accept-new \
-v "$host" exit </dev/null 2>&1 | sed -n 's/.*kex: algorithm: //p' | head -1)
case "$alg" in
mlkem*) printf '%-38s PQ-ML-KEM %s\n' "$host" "$alg" ;;
sntrup*) printf '%-38s PQ-LEGACY %s\n' "$host" "$alg" ;;
"") printf '%-38s UNREACHED (auth, firewall or timeout)\n' "$host" ;;
*) printf '%-38s CLASSICAL %s\n' "$host" "$alg" ;;
esac
done < hosts.txt
# PQ-ML-KEM -> done, nothing to do.
# PQ-LEGACY -> safe today (sntrup761 is quantum-resistant) but not the NIST
# standard; schedule the upgrade to OpenSSH 9.9+ anyway.
# CLASSICAL -> this is your harvest-now-decrypt-later exposure. Fix first.第二步:小心地改配置
有了普查结果,改动本身很小。把它放进一个 drop-in 文件,而不要去编辑主配置,这样这处改动可被 grep、可回滚,而且显然是你做的:[sshdcfg][ssh99]
# /etc/ssh/sshd_config.d/50-post-quantum.conf
# Requires `Include /etc/ssh/sshd_config.d/*.conf` in the main sshd_config,
# which Debian, Ubuntu, RHEL and Fedora already ship. Check with:
# grep -r '^Include' /etc/ssh/sshd_config
# --- OpenSSH 9.9 and newer ---
# Post-quantum first, classical last. The list is ordered by preference, and
# the two hybrids are the only entries here that resist a quantum adversary.
KexAlgorithms mlkem768x25519-sha256,sntrup761x25519-sha512,curve25519-sha256,curve25519-sha256@libssh.org
# --- OpenSSH 9.0 to 9.8: NEITHER name above exists on those builds. ---
# ML-KEM only arrived in 9.9, and until 9.9 the NTRU Prime hybrid existed
# solely under its vendor extension name. sshd refuses to start on an
# unknown algorithm name, so on those versions use exactly this line and
# nothing from the one above:
# KexAlgorithms sntrup761x25519-sha512@openssh.com,curve25519-sha256
# Confirm which names your build accepts before editing: ssh -Q kex
# Signatures are NOT the urgent problem (see the article), but this is a good
# moment to drop the algorithms that are weak for classical reasons too.
HostKeyAlgorithms ssh-ed25519,ssh-ed25519-cert-v01@openssh.com,rsa-sha2-512,rsa-sha2-256
PubkeyAcceptedAlgorithms ssh-ed25519,ssh-ed25519-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,rsa-sha2-512,rsa-sha2-256
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com
# --- Validate BEFORE reloading, and keep your current session open. ---
# sudo sshd -t && sudo systemctl reload ssh # or sshd, depending on the distro
# Then open a SECOND session and confirm it works before closing the first.不要跳过验证仪式。reload 之前先跑
sshd -t,保持当前会话不要关闭,另开第二个会话确认成功后再关第一个。KexAlgorithms 里一个笔误就会把你锁在主机外面,而在没有控制台访问的机器上,那不是一次故障,是一次重装。
客户端这一侧你可以更严格,因为在自己笔记本上大声失败是可以承受的,在共享跳板机上则不行。经得起现实检验的写法是:一个严格的默认值,加上明确且带日期的例外:[sshcfg]
# ~/.ssh/config - client side
#
# ssh_config is FIRST-OBTAINED-VALUE-WINS, not last. The specific block must
# come BEFORE `Host *`, otherwise the general block wins and the exception
# below is silently dead. This is the single most common mistake in hardened
# client configs, and it fails in the direction you will not notice.
# Exceptions first: the boxes you have not fixed yet. Make each one explicit
# and dated, so it shows up in review instead of quietly becoming permanent.
Host legacy-nas.internal jump-2019.example.com
# TODO(2026-11-30): appliance firmware pending, ticket OPS-4471
# Note this REPLACES the list rather than using `+`, which would append to
# the full compiled-in default and quietly re-enable every modp group.
KexAlgorithms curve25519-sha256,diffie-hellman-group-exchange-sha256
WarnWeakCrypto no-pq-kex
# ...and the hard default for everything else.
Host *
KexAlgorithms mlkem768x25519-sha256,sntrup761x25519-sha512
WarnWeakCrypto yes
# Verify the result rather than trusting the file. `ssh -G` prints the
# effective configuration for a given destination, after all matching:
# ssh -G legacy-nas.internal | grep -i '^kexalgorithms'
# ssh -G anything-else.example.com | grep -i '^kexalgorithms'两个值得内化的细节。第一,OpenSSH 实现的所有后量子算法都是混合的:mlkem768x25519-sha256 把 ML-KEM 与 X25519 一起跑并合并结果,所以即便未来的密码分析攻破了 ML-KEM,结果也不会比你之前用的经典交换更弱。不存在吃亏的情形。第二,如果你卡在 OpenSSH 9.x 上无法升级,NTRU Prime 混合算法从 9.0 起就可用且抗量子——但要注意名字:9.9 之前它只以 sntrup761x25519-sha512@openssh.com 的形式存在,短名称会被拒绝。它不是 NIST 标准,但它今天就能挡住窃取式攻击,而这正是重点。[pq]
修好 TLS
TLS 的形状一样,只是抓手不同。原语在 OpenSSL 里,不在你的 Web 服务器里:只要 OpenSSL 3.5 或更新,就不需要补丁、不需要 oqs-provider、不需要 fork 过的 nginx。先确认库版本,因为大多数意外都藏在这里——发行版完全可能提供一个很新的 nginx,却链接到一个根本做不了 ML-KEM 的 OpenSSL。[ossl35][tlsdraft][mlkemkex]
# 1. ML-KEM needs OpenSSL 3.5.0 or newer. No 3.x before 3.5 can do it at all,
# however recent the rest of the stack looks.
openssl version
# OpenSSL 3.5.7 9 Jun 2026
# 2. Confirm the provider actually exposes the primitives.
openssl list -kem-algorithms | grep -i mlkem
openssl list -signature-algorithms | grep -iE 'ML-DSA|SLH-DSA'
# 3. What does a live endpoint negotiate when the client offers the hybrid?
openssl s_client -connect www.example.com:443 -servername www.example.com \
-groups X25519MLKEM768 -tls1_3 </dev/null 2>/dev/null \
| grep -E 'Negotiated TLS1.3 group|Protocol :|Cipher :'
# Negotiated TLS1.3 group: X25519MLKEM768
# 4. Control test: the same endpoint must still serve a classical-only client,
# otherwise you have not hardened it, you have broken it.
openssl s_client -connect www.example.com:443 -servername www.example.com \
-groups X25519 -tls1_3 </dev/null 2>/dev/null \
| grep 'Negotiated TLS1.3 group'
# Negotiated TLS1.3 group: X25519注意第四步的对照测试。启用混合组不应该打断经典客户端;如果打断了,说明你把列表配错了,而不是加固了什么。顺序重要,排他性不重要:把混合组放在最前,经典曲线留在后面。[osslgroups]
# Pick the ONE stanza that matches your terminator - this is four different
# config syntaxes in one block, not a file you can paste as-is.
### nginx (built against OpenSSL 3.5+; no patches, no oqs-provider needed)
# ssl_ecdh_curve feeds the TLS supported-groups list. Hybrid first, then the
# classical curves that keep older clients working.
ssl_protocols TLSv1.3 TLSv1.2;
ssl_ecdh_curve X25519MLKEM768:X25519:secp256r1;
ssl_prefer_server_ciphers off;
### HAProxy 3.x
ssl-default-bind-curves X25519MLKEM768:X25519:secp256r1
### Apache httpd (mod_ssl passes the list straight to OpenSSL)
SSLOpenSSLConfCmd Groups X25519MLKEM768:X25519:P-256
### OpenSSL system-wide default, for everything that reads openssl.cnf
# [openssl_init] -> ssl_conf -> system_default
Groups = X25519MLKEM768:X25519:secp256r1配置就是每个服务器一行,而且在所有情况下喂给的都是同一份 OpenSSL 支持组列表:[nginxssl][haproxy][osslconf]
| 组件 | 前提条件 | 常见陷阱 |
|---|---|---|
| nginx | 链接 OpenSSL 3.5.0+;ssl_ecdh_curve | 很新的 nginx 却编译在 OpenSSL 3.0 上——要看 nginx -V,不是 nginx 版本号。 |
| HAProxy | OpenSSL 3.5.0+;ssl-default-bind-curves | 每个 bind 上的覆盖会静默地压过默认行。 |
| Apache httpd | OpenSSL 3.5.0+;SSLOpenSSLConfCmd Groups | 该指令按虚拟主机生效;没写的 vhost 会继承编译期默认值。 |
| CDN / 托管负载均衡 | 厂商侧开关,通常已经打开 | 它后面到源站那一段是你的,而且通常就是还在用经典算法的那一段。 |
| 应用运行时(Go、Java、Node) | 运行时自带的 TLS 栈,不是系统 OpenSSL | 以为系统库说了算。很多时候并不算。 |
架构上唯一要想清楚的一点:这一切只适用于 TLS 被终结的地方。如果 CDN 或负载均衡器替你终结,那么需要混合组的是那一跳,而你的源站配置是另一个问题——两者之间那条链路同样是另一个问题,而它恰恰就是最常被遗忘的内部段。如果你在 Kubernetes 里终结,这件事属于网关,而从 ingress-nginx 迁移出去正是顺手做掉它的自然时机,反正那些对象你都要重写。[rfc8446]
做一份经得起审计的清单
上面讲的都是单台主机。审计人员——以及未来的你——真正会问的是覆盖率:不是「这个端点修好了吗」,而是「一共有多少个,哪些还没修」。用你本来就信任的事实来源来生成这份清单,而不要用网络扫描,这样「不在清单上」才有意义:
#!/usr/bin/env bash
# pq-inventory.sh - a starting point, not a CBOM. One line per listener, with
# the negotiated group, so the output diffs cleanly between runs.
set -uo pipefail
printf '%-34s %-9s %-22s %s\n' HOST PORT GROUP NOTE
while IFS=: read -r host port; do
out=$(openssl s_client -connect "$host:$port" -servername "$host" \
-groups X25519MLKEM768:X25519 -tls1_3 </dev/null 2>/dev/null)
grp=$(printf '%s' "$out" | sed -n 's/^Negotiated TLS1.3 group: //p')
sig=$(printf '%s' "$out" | sed -n 's/^Peer signature type: //p')
case "$grp" in
*MLKEM*) note="pq-ok" ;;
"") note="no-tls1.3-or-unreachable" ;;
*) note="classical-only" ;;
esac
printf '%-34s %-9s %-22s %s (sig %s)\n' "$host" "$port" "${grp:--}" "$note" "${sig:--}"
done < endpoints.txt
# endpoints.txt is one host:port per line. Feed it from whatever you already
# trust as the source of truth - the load balancer config, Consul, the CMDB -
# rather than from a network scan, so that absence is meaningful.在跑过类似的东西之前,先忍住不要采购密码物料清单(CBOM)产品。相关工具确实在变好,但第一遍值得手工做,因为它让你看清自己资产的形状,而这恰恰是任何厂商都给不了你的。工作顺序:
- 对外 TLS 终结点。所有公网主机名。清单最短,暴露面最大,通常在边缘改一处就解决了。
- SSH,全部。先跳板机,再是从跳板机可达的一切。设备、网络硬件和被遗忘的虚拟机组成的长尾就在这里浮出来。
- 内部服务间 TLS。服务网格、数据库连接、消息中间件。清单更长、更难枚举,同时也是网格自身默认值可能已经替你解决了问题的地方。
- VPN 与站点间隧道。生命周期长、价值高,而且经常跑在有自己升级节奏的厂商固件上。尽早跟供应商谈,因为这更像采购问题而不是技术问题。
- 所有嵌入式设备。各类设备、代理、打印机、摄像头、工业控制器。把它们记录下来,明确接受风险,并给这份接受加上日期。
让输出可以做 diff,并定期重跑。一个朝错误方向变化的数字,是最早的信号:某个重建的镜像或回滚的软件包悄悄把工作抹掉了——而这种失败远比一次搞砸的迁移更常见。
签名与证书:为什么现在应该等
接下来是「有用的建议是少做点」的部分。NIST 在 2024 年标准化了两种后量子签名方案 ML-DSA 与 SLH-DSA,两者在 OpenSSL 3.5 中都已实现。你今天就能生成密钥。但你不该把它们放进证书链。[fips204][fips205][fips203]
理由就是 OpenSSH 解释自己为何优先做密钥协商时给出的那个:不存在「先存储、后伪造」的攻击。签名只需要在被验证的那一刻不可伪造。签名的紧迫性不在于保护今天的流量,而在于确保经典签名密钥在具备密码学意义的量子计算机出现之前退役——这个期限以年计,而不是以抓到的数据包计。[pq]
实际的阻塞点都是生态形状的,没有一个是你能解决的:
- 浏览器不信任任何后量子根。证书链的价值取决于验证方是否已经信任那个根,而这些信任库出于充分理由是以数年为周期演进的。
- 体积问题是真实存在的。ML-DSA 的签名和公钥都明显大于 ECDSA。在需要传输完整链的握手里,这在丢包链路上体现为额外的往返,而不是抽象的字节数。
- OpenSSH 目前只有实验性的后量子签名方案。项目在 10.1 中移除了实验性的 XMSS 支持,随后在 10.4(2026 年 7 月)加入了把 ML-DSA-44 与 Ed25519 组合起来的复合方案
mldsa44-ed25519。它被明确标注为实验性,而且默认不启用:你需要自己把它加进HostKeyAlgorithms和PubkeyAcceptedAlgorithms,并用ssh-keygen -t mldsa44-ed25519生成密钥。值得知道,但还不值得放到生产环境的主机密钥下面。[ssh104][mldsased][ssh101] - 每个中间环节都必须同意。证书校验牵涉到你的服务器、客户端、每一个做检查的中间设备,以及某人在 2019 年加上的任何 pinning。签名是失败即关闭,而且是所有人同时失败。
那 2026 年该拿签名怎么办?两件事,都不贵。一是淘汰那些因为经典原因就已经很弱的算法:DSA 在 OpenSSH 10.0 中被彻底移除,SHA-1 签名本来早就该走了。二是让证书签发自动化并缩短有效期,这样等后量子证书真的可以签发时,替换它只是一次配置变更而不是一个项目。密码敏捷性不是买来的产品,而是「已经能快速轮换」这个属性——你本来就该为了完全无关的理由想要它。这里适用的直觉和无聊的架构背后那一套是一样的:奇特的选项不是安全的选项。[ssh103]
监管时间表,准确版
时间表是技术文章最容易悄悄写错的地方,所以这里给出严谨版本。人人引用来支持「RSA 在 2030 年被弃用」的那份文件 NIST IR 8547,是 2024 年 11 月发布的初始公开草案。它的意见征询期在 2025 年 1 月结束,收到的意见是公开的。它表明了 NIST 预期采取的路径,是正确的规划输入——但把它当作最终的、有约束力的标准来引用是不准确的,而你评审会上一定有人知道这一点。[ir8547]
| 文件 | 状态 | 实际内容 |
|---|---|---|
| NIST IR 8547 | 初始公开草案,2024 年 11 月 | 提出 RSA、ECDSA、ECDH 与有限域 DH 在 2030 年后弃用、2035 年后禁用。是草案,不是最终标准。 |
| FIPS 203 / 204 / 205 | 正式发布,2024 年 8 月 | ML-KEM、ML-DSA 与 SLH-DSA。其他所有文件引用的都是这几个算法。 |
| 欧盟协调路线图 | 成员国通过,2025 年 6 月 | 2026 年底前启动迁移并开展试点;2030 年前完成高风险与关键基础设施;2035 年前尽可能完成。 |
| 你所在行业的监管方 | 各不相同 | 通常派生自上述之一。要读那份派生文件,而不是摘要。 |
这个区分在实践中很重要:草案告诉你底线在往哪个方向移动,这足够用来做规划;但不足以让你在设计文档里写「NIST 要求」。按它本来的性质引用它,你的方案就能挺过第一次认真的评审。[ir8547]
欧洲走的是一条机制不同的平行路线。成员国通过 NIS 合作组通过了一份协调实施路线图,结构大致是:2026 年底前启动迁移并开展试点;2030 年前完成高风险场景与关键基础设施;2035 年前在可行范围内尽量完成。它是协调工具而不是法规,但各国路线图正是照着它写的,所以如果你在欧盟运营,这就是你的行业监管方读过的那份文件。[euroadmap]
对面向中国大陆的部署还要补一句:国内的商用密码体系有自己的算法族与合规路径,与本文讨论的国际开源栈(OpenSSH、OpenSSL)是两条线,不能互相替代着理解。如果你的系统同时要满足国内合规与国际互联互通,正确做法是分别核对各自现行的官方文件,而不是从任何一方的英文摘要里推导——同时预留出厂商固件的时间,因为在上述每一份时间表里,固件都是那个真正卡住进度的约束。设备如果按五年更换周期走,今年这笔采购就已经是一个后量子决定了,不管采购流程里有没有人这么说。
一个 90 天计划
如果你想把整件事压进一页,就是下面这张表。前提是:密钥协商是一个已经解决、你只是在推广的问题,其余都是准备工作。
| 阶段 | 工作内容 | 完成标志 |
|---|---|---|
| 第 1–2 周 普查 | 扫描 SSH 与 TLS 的协商算法,而不是支持列表。用你自己的事实来源建立端点清单。 | 你手上有了一个数字:多少端点仍是经典的,分别是哪些。 |
| 第 3–6 周 对外边缘 | 每个公网 TLS 终结点和每台跳板机。确认二进制实际链接的是哪个 OpenSSL。 | 对外协商出混合组,且经典客户端仍然可用。 |
| 第 7–10 周 内部 | 服务间 TLS、复制、备份,以及 CDN 后面的回源段。那些没有人会看到告警的链路。 | 内部的数量和对外的对上了。 |
| 第 11–12 周 残余风险 | 修不了的设备与固件。已开厂商工单,风险书面接受,复核日期已定。 | 每一条剩余例外都有责任人和日期。 |
| 持续 签名 | 把证书签发自动化并缩短有效期。不要部署后量子证书。 | 你能在不开变更窗口的情况下轮换任意一张证书。 |
对多数资产规模来说,前三个阶段用九十天是现实的,因为改动很小,风险集中在普查而不是编辑上。真正拖时间的永远是同样两件事:升不动的设备,和没人知道存在的链路。只要清单做得认真,这两样在第一周就会浮出来——这正是先做清单的理由。
五个值得避开的坑
真实迁移里反复出现的模式,大致按浪费的时间排序:
- 审计能力而不是审计协商结果。「我们的服务器支持 ML-KEM」不是一条结论。服务器可以支持它,同时整天为某个老客户端完成经典握手。要读连接上协商出来的算法,不是支持列表。
- 把经典算法删掉。混合算法存在的意义,恰恰是让你不必二选一。后量子组放前面,X25519 留在后面,你就能在不引发可用性事故的前提下拿到保护。
- 追着证书跑。2026 年花在尝试部署 ML-DSA 证书上的时间,就是没有花在真正被窃取的那个交换上的时间。去把签发自动化,那才是以后会回本的活。
- 只做到边缘为止。CDN 那一跳的握手是后量子的,回源那一段不是。这是最常见的缺口,因为外部测试能通过,而内部那一段没有用户会来投诉。
- 把它当成一次性工作。一个重建的基础镜像、一个被 pin 住的软件包、一次配置回滚,三月还合规的主机到九月就在用经典算法协商了。把扫描挂到定时器上,并在数量回升时告警。
简版结论
后量子密钥协商不是一个未来项目。它是一个你多半已经继承下来的默认值,而全部工作就是把漏掉它的那些连接找出来。升级到 OpenSSH 10.x 与 OpenSSL 3.5+,在两边都把混合组放到最前,扫一遍机群看实际协商出的是什么,然后把例外连同日期一起写下来。对多数团队这是一周的工作量,而它关掉了这个领域里今天唯一正在发生的攻击。
然后就停手。不要迁证书,不要买密码敏捷性平台,也不要在战略文档里写「量子」。把证书签发做成自动且短周期的,把清单维护成最新的,然后等生态跟上——因为当后量子签名真正可部署时,处理得好的组织不会是最早开始的那些,而是那些今天就已经能不开变更窗口换证书的组织。
常见问题
我已经在用 OpenSSH 10,还需要做什么吗?
先验证,然后大概率不需要。默认值是 mlkem768x25519-sha256,但一份加固基线、一个从 CIS 派生的模板,或者某个配置管理模块,可能写过自己的 KexAlgorithms 行——它早于 ML-KEM,会静默地把它排除掉。对着一台真实主机跑 ssh -v host exit 2>&1 | grep 'kex: algorithm',读协商结果。对入站会话来说,起决定作用的是服务端。
启用后量子密钥交换会不会打断老客户端?
只要你把它配置成偏好而不是限制,就不会。SSH 的 KexAlgorithms 和 TLS 的支持组列表都是有序偏好:把混合算法放最前,curve25519-sha256 或 X25519 留在后面,现代对端会拿到后量子交换,老的则回落。真正会出问题的是你把经典条目整个删掉——对一支完全受控的封闭机群这是可辩护的选择,对任何公网服务都是坏选择。
sntrup761x25519-sha512 够用吗,还是必须换成 ML-KEM?
它确实抗量子,而且今天就能挡住先窃取后解密的攻击,这正是你需要的性质。它的弱点在标准化而不在密码学:NTRU Prime 未被 NIST 选中,所以无法满足围绕 FIPS 203 写就的合规要求,长期的实现支持也更不确定。如果你在 OpenSSH 9.0–9.8 上且本季度无法升级,你是受保护的。但仍然要把升到 9.9+ 排进计划。
为什么现在不能直接部署后量子证书?
因为证书只有在验证方已经信任签发它的根时才有用,而浏览器信任库里没有任何后量子根。你可以用 OpenSSL 3.5 生成 ML-DSA 密钥并用它搭一个内部 CA,对封闭系统来说这是合理的实验。但只要是浏览器会碰到的东西,证书链就通不过校验。这是生态的先后次序问题,不是配置问题,要用年来解决。
怎么查我的 TLS 端点实际协商出了什么?
openssl s_client -connect host:443 -servername host -groups X25519MLKEM768 -tls1_3 </dev/null 2>/dev/null | grep 'Negotiated TLS1.3 group'。测试本身需要 OpenSSL 3.5+ 的客户端:用更老的客户端测会得到假阴性,因为你的客户端根本没提供过这个组。另外一定要用 -groups X25519 再跑一次对照测试,确认你是加固了端点而不是弄坏了它。
AES 和 SHA-256 需要担心吗?
不需要。Grover 算法对对称原语提供平方级加速,实际效果相当于把密钥长度减半:AES-256 仍保有 128 位的安全余量,SHA-256 依然足够。AES-128 争议更多,但不是实际关切。被 Shor 算法直接攻破的是非对称算法——RSA、ECDH、ECDSA——而它们正是本文的全部主题。
VPN、数据库和消息队列怎么办?
规则相同,执行更难。WireGuard 的基础协议里没有后量子密钥协商,需要依赖它的预共享密钥机制来构成混合方案。IPsec 的支持完全取决于你厂商的固件。数据库和消息中间件的 TLS 通常跟随运行时自带的 TLS 栈,而不是系统 OpenSSL,所以要逐个验证,不要假设一个系统级设置已经生效到那里。这些链路同时也是价值最高的目标,因为它们承载的正是窃取式攻击想要收集的那种长生命周期机密数据。
这是合规表演,还是真实威胁?
威胁是真实的,只是在时间上被推后了,所以很容易在两个方向上误判。今天没有人在解密你的流量。真正的问题是:今天被抓走的流量,到 2030 年代中期是否仍然敏感?对病历、金融数据、法律材料、政务通信和长期凭据来说,答案显然是「是」。这个风险特别之处在于缓解措施几乎不要钱——一次版本升级加一行配置——所以成本收益的算式并不要求你相信任何一个具体的到来日期。
以上都假定基础系统不会变,但它会变:Ubuntu 24.04 升级到 26.04 的服务器实践 一文说明了那次会替换其中六项默认值的版本升级。
参考来源
下列来源都是在写作本文时实际阅读过的。优先引用项目的发布说明与标准化文件,而不是二手报道;当某份文件只是草案而非最终标准时,文中会明确说明。
- OpenSSH — Post-Quantum Cryptography (project page, FAQ and warning text)
- OpenSSH 9.9 release notes (19 September 2024) — ML-KEM hybrid added; sntrup761x25519-sha512 gains its IANA name
- OpenSSH 10.0 release notes (9 April 2025) — mlkem768x25519-sha256 becomes the default key agreement
- OpenSSH 10.1 release notes (6 October 2025) — warning on non-post-quantum key agreement, WarnWeakCrypto
- OpenSSH 8.5 release notes (3 March 2021) — sntrup761x25519-sha512@openssh.com replaces the older NTRU Prime hybrid, disabled by default
- OpenSSH 10.3 release notes (2 April 2026)
- OpenSSH 10.4 release notes (6 July 2026) — experimental mldsa44-ed25519 composite post-quantum signature scheme, not enabled by default
- OpenSSH 10.5 release notes (11 August 2026) — current release at the time of writing
- OpenSSH — full release notes index
- ssh_config(5) — KexAlgorithms, WarnWeakCrypto, Match
- sshd_config(5) — KexAlgorithms, HostKeyAlgorithms, Include
- IETF draft-ietf-sshm-mlkem-hybrid-kex — hybrid ML-KEM key exchange for SSH
- IETF draft-ietf-sshm-ntruprime-ssh — sntrup761x25519-sha512 for SSH (successor to the expired draft-josefsson document)
- IETF draft-miller-sshm-mldsa44-ed25519-composite-sigs — the composite signature scheme OpenSSH 10.4 implements
- OpenSSL 3.5 series release notes — PQC support and hybrid groups preferred by default (3.5.0, 8 April 2025)
- OpenSSL documentation — SSL_CTX_set1_groups_list(3), the TLS supported-groups list
- OpenSSL documentation — SSL_CONF_cmd(3), the Groups command Apache passes through
- nginx documentation — ssl_ecdh_curve in ngx_http_ssl_module
- HAProxy configuration manual — ssl-default-bind-curves
- IETF draft-ietf-tls-ecdhe-mlkem — hybrid ECDHE + ML-KEM groups for TLS 1.3
- RFC 8446 — The Transport Layer Security (TLS) Protocol Version 1.3
- NIST FIPS 203 — Module-Lattice-Based Key-Encapsulation Mechanism Standard (ML-KEM)
- NIST FIPS 204 — Module-Lattice-Based Digital Signature Standard (ML-DSA)
- NIST FIPS 205 — Stateless Hash-Based Digital Signature Standard (SLH-DSA)
- NIST IR 8547 (Initial Public Draft, 12 November 2024) — Transition to Post-Quantum Cryptography Standards
- European Commission / NIS Cooperation Group — Coordinated Implementation Roadmap for the Transition to PQC
- Cloudflare — State of the post-quantum Internet in 2025
- Cloudflare Radar — post-quantum encryption adoption (live figures)
这篇有帮助吗?