协议特性

TLS 1.3 详解:相比 1.2 改了什么、怎么开启

作者: · 最后核实

TLS 1.3 是传输层安全协议的当前版本,最初于 2018 年 8 月以 RFC 8446 发布,现行规范是 2026 年 7 月的 RFC 9846。和 TLS 1.2 相比,新连接只要 1 个往返,握手大部分内容(包括服务器证书)都被加密,过去十年引发过攻击的老算法全部删除。截至 2026 年 11 月,主流浏览器、操作系统和 TLS 库都已支持,服务器应开启 TLS 1.3,同时保留加固过的 TLS 1.2 兼容老客户端。

和 TLS 1.2 相比改了什么

TLS 1.3 是一次重新设计,删掉的东西比新增的多。

方面 TLS 1.2(RFC 5246,现已被 RFC 9846 取代) TLS 1.3(RFC 9846,最初为 RFC 8446)
完整握手 2 个往返 1 个往返
会话恢复 Session ID 或票据,1 个往返 PSK 票据,可选 0-RTT
密钥交换 静态 RSA、DHE、ECDHE 只有临时 (EC)DHE 或混合算法,或 PSK + (EC)DHE
前向保密 只有 (EC)DHE 套件才有 完整握手始终具备
加密算法 CBC、RC4、3DES、GCM、ChaCha20…… 只有 AEAD:AES-GCM、ChaCha20-Poly1305、AES-CCM
密码套件 数百种组合 5 个
DH 参数 服务器可以发任意参数 只能用命名组(X25519、P-256、RFC 7919 的 FFDHE……)
握手签名 允许 RSA PKCS#1 v1.5、SHA-1、MD5 RSA-PSS、ECDSA、EdDSA;PKCS#1 v1.5 仅限老式客户端密钥(RFC 9963);不再用 SHA-1、MD5
证书 明文发送 加密发送
压缩 支持(CRIME,2012) 删除
重协商 支持 删除,由 KeyUpdate 和握手后认证代替
ChangeCipherSpec 真实的协议消息 删除(为兼容中间设备保留一个假消息)
密钥派生 自定义 PRF HKDF + 结构化密钥调度

删掉的东西都不是摆设:静态 RSA 密钥交换没有前向保密,还招来了 ROBOT(2017)这类 Bleichenbacher 式攻击;CBC 填充招来了 Lucky Thirteen;压缩招来了 CRIME;重协商在 2009 年需要紧急打补丁;任意 DH 参数招来了 Logjam。每一项删除关掉的是一整类漏洞。

2026 年 7 月,IETF 把 TLS 1.3 重新发布为 RFC 9846。这是一次向后兼容的小修订,版本号不变:澄清了含糊的条文,禁止在不同连接之间复用 key share,禁止协商 TLS 1.0 和 1.1,限制 KeyUpdate 消息的数量,新增 general_error 告警,并把 "master" secret 的叫法改为 "main"。它同时取代了 RFC 5246,TLS 1.2 的实现要求也写进了同一份文档。

更快:1-RTT 与 0-RTT

TLS 1.3 靠“客户端先猜”省掉一个往返。ClientHello 里已经带了客户端估计服务器会接受的 key share,服务器第一次回复就能算出密钥,并把证书、签名和 Finished 一起发回来。客户端发出自己的 Finished 后马上就能发 HTTP 请求,前后只用 1 个往返。

TLS 1.2 完整握手                            TLS 1.3 完整握手
C: ClientHello              --->            C: ClientHello + key_share      --->
S: ServerHello, Certificate,                S: ServerHello + key_share,
   ServerKeyExchange,                          {EncryptedExtensions,
   ServerHelloDone          <---               Certificate, CertificateVerify,
C: ClientKeyExchange,                          Finished}                     <---
   ChangeCipherSpec, Finished --->          C: {Finished} + [GET /]         --->
S: ChangeCipherSpec, Finished <---          S: [200 OK]                     <---
C: [GET /]                  --->
S: [200 OK]                 <---
   = 发请求前 2 个往返                         = 发请求前 1 个往返

猜错了服务器就回 HelloRetryRequest,握手变成 2 个往返,也不比 TLS 1.2 差。每条消息的细节见 TLS 握手详解。

恢复会话时还能更进一步用 0-RTT:客户端用上次会话票据里的预共享密钥,在第一个包里就带上应用数据。代价在安全上:早期数据无法防重放,因为服务器没法确认它是新鲜的;它相对票据密钥也没有前向保密。TLS 1.3 规范要求应用显式开启,RFC 8470 规定了 HTTP 的处理方式:Early-Data: 1 请求头和 425 Too Early 状态码。大多数服务器默认关闭 0-RTT,Nginx 的 ssl_early_data 默认就是 off。见 0-RTT。

更隐私:握手被加密

TLS 1.3 中 ServerHello 之后的一切都加密,包括服务器证书链。在 TLS 1.2 下,被动观察者能直接从线路上读到证书,也就知道了 SAN 里的所有域名;TLS 1.3 下它只能看到 ClientHello 和 ServerHello。

剩下的泄露点是 ClientHello 里的 SNI:服务器得先知道域名才能选证书。加密 ClientHello(ECH,2026 年 3 月标准化为 RFC 9849)补上了这个缺口:客户端从 HTTPS DNS 记录里取得服务器的 ECH 公钥,把真正的 ClientHello 加密后包在一个只写公共前端域名的外层 ClientHello 里。ECH 只能在 TLS 1.3 上用,这也是升级的理由之一。

降级保护

如果攻击者能让双方都以为对方只支持 TLS 1.2,就可能把连接引向更弱的算法。TLS 1.3 有两层防护。

第一层,真实版本在 supported_versions 扩展里协商,整个握手又被 Finished 和服务器签名保护。第二层,支持 TLS 1.3 的服务器一旦协商出更低版本,会在 ServerHello random 的最后 8 字节写入标记:

支持 1.3 的服务器协商到 TLS 1.2:   44 4F 57 4E 47 52 44 01   ("DOWNGRD" 01)
协商到 TLS 1.1 或更低:             44 4F 57 4E 47 52 44 00   ("DOWNGRD" 00)

server random 在服务器签名范围内,攻击者删不掉这个标记,支持 TLS 1.3 的客户端看到它就中止连接。它取代了早先的 TLS_FALLBACK_SCSV(RFC 7507),后者只能防住浏览器自己降版本重试那一种情况。

中间设备兼容模式

TLS 1.3 握手被故意伪装成 TLS 1.2 的会话恢复。标准制定期间的实测发现,不少防火墙、代理和流量审计设备会丢弃“看起来不像 TLS 1.2”的连接,所以最终设计里加了几层伪装:

  • ClientHello.legacy_version 固定写 0x0303(TLS 1.2),真实版本列表放在 supported_versions;
  • 记录层头部也写 0x0303,加密记录的外层类型一律是 application_data;
  • 客户端发送随机的 32 字节 legacy_session_id,服务器原样回显;
  • 双方各发一条没有意义的 ChangeCipherSpec。

所以抓 TLS 1.3 的包会看到“TLS 1.2”的记录头和 ChangeCipherSpec。openssl s_client -msg 输出里出现 <<< TLS 1.2, RecordHeader 后面跟着 <<< TLS 1.3, ChangeCipherSpec 是正常的。国内企业网常见的上网行为管理、SSL 解密网关如果版本太老,正是这类兼容问题的高发区。

后量子密钥交换只在 TLS 1.3 上

新的密钥交换方式以命名组的形式加入 TLS 1.3,不需要改密码套件。最重要的是 X25519MLKEM768(编号 0x11EC),由 X25519 和 NIST 标准化的 ML-KEM-768 组合而成,2026 年 8 月与 SecP256r1MLKEM768、SecP384r1MLKEM1024 一起在 RFC 10024 中标准化。Chrome 131 于 2024 年 11 月默认启用,2025 年 4 月发布的 OpenSSL 3.5 也把它放进了默认 key share。这些混合算法只为 TLS 1.3 定义,停留在 TLS 1.2 的服务器根本无法提供抗量子的密钥交换。详见后量子 TLS。

哪些东西不变

开启 TLS 1.3 不需要换证书、换私钥或改证书链。同一张 RSA 或 ECDSA 证书可以同时服务 TLS 1.2 和 TLS 1.3 客户端;OCSP 装订和 SCT 照常工作(改为挂在 Certificate 条目的扩展里);HSTS 等 HTTP 层设置不受影响;ALPN 照样协商 h2 或 http/1.1,HTTP/2 无需改动。

RSA 密钥在 TLS 1.3 下有一条限制:TLS 1.3 服务器的 RSA 密钥必须用 RSA-PSS 签握手,哪怕证书本身是 PKCS#1 v1.5 签发的;最初的 RFC 8446 对客户端也是同样要求。软件密钥对此无感,但一些老的硬件加密模块、智能卡、USB Key 和 TPM 里的客户端密钥只能做 PKCS#1 v1.5 签名。RFC 9963(2026 年 4 月)为这类客户端密钥新增了 rsa_pkcs1_*_legacy 编号,服务器可以在 CertificateRequest 里提供。客户端或服务器任一方没实现 RFC 9963 时,这类密钥仍是在 TLS 1.2 下正常、到了 TLS 1.3 就失败,典型表现是升级后基于客户端证书的登录(比如网银、政务系统常见的 U 盾类方案)突然不能用。ECDSA 密钥没有这个问题。

会话恢复的形态也变了:TLS 1.2 的 Session ID 和票据换成了 TLS 1.3 的 PSK 票据。负载均衡后的多台服务器仍要同步票据密钥,而旧的 Session ID 缓存对 TLS 1.3 客户端不再起作用。

谁支持 TLS 1.3

当前版本的软件全都支持,问题出在老环境上。

软件 首个支持正式版 TLS 1.3 的版本
OpenSSL 1.1.1(2018 年 9 月)
Chrome 70
Firefox 63
Safari 12.1
Android 10
Java 11(并向后移植到 8u261)
Windows(Schannel) Windows 11、Windows Server 2022
Apache httpd 2.4.36,需 OpenSSL 1.1.1
Nginx 1.13.0,需 OpenSSL 1.1.1

薄弱环节是 TLS 库早于 2018 年的服务器。CentOS 7、RHEL 7 自带 OpenSSL 1.0.2,国内不少老服务器还跑着它;Windows Server 2019 及更早版本的 Schannel 没有 TLS 1.3,IIS 站点要升级系统。Java、Go 这类自带 TLS 实现的软件不受系统 OpenSSL 影响。

怎么开启 TLS 1.3

在较新的环境里,开启 TLS 1.3 只是在协议列表里加一个词。

# Nginx(需用 OpenSSL 1.1.1 或更高版本编译)
ssl_protocols TLSv1.2 TLSv1.3;
# Apache httpd 2.4.36+,OpenSSL 1.1.1+
SSLProtocol -all +TLSv1.2 +TLSv1.3

先确认库版本:nginx -V 2>&1 | grep -i openssl 能看到 Nginx 编译时用的 OpenSSL;Apache 可以用 httpd -V 和 apachectl -M。然后从外部验证:

openssl s_client -connect example.com:443 -servername example.com -tls1_3 -brief </dev/null
curl -sv --tlsv1.3 -o /dev/null https://example.com/ 2>&1 | grep -E 'SSL connection|TLSv1.3'

服务器不支持 TLS 1.3 时,s_client 会因协议版本告警而失败。SSL 检测工具会列出支持的版本,套件与协议命令手册里有逐个版本测试的命令。

国内常见环境:

  • 宝塔面板:网站设置的 SSL 页面通常可以勾选 TLS 版本,也可以直接改配置文件里的 ssl_protocols。改完用上面的命令从外网验证一次。
  • CentOS 7 自编译 Nginx:系统 OpenSSL 1.0.2 不能用,编译时用 --with-openssl= 指向新版 OpenSSL 源码,或者迁移到更新的发行版。
  • 阿里云、腾讯云负载均衡与 CDN:在 HTTPS 监听或域名配置里选择包含 TLS 1.3 的安全策略。这时源站配置不影响访客,访客只和边缘节点握手。

常见部署问题

大多数 TLS 1.3 问题出在 Web 服务器外围,而不是协议本身。

  • 对外的不是你的服务器:CDN、云负载均衡或 WAF 终止 TLS 时,协议由它们的策略决定,源站 Nginx 怎么配访客都看不到。
  • 只开 TLS 1.3 会挡掉老客户端:Mozilla modern 配置列出的最老客户端是 Firefox 63、Chrome 70、Safari 12.1、Android 10、Java 11。更老的安卓手机、旧版 Java 程序、嵌入式设备会报 ERR_SSL_VERSION_OR_CIPHER_MISMATCH 或笼统的协议错误。
  • 按路径要客户端证书:TLS 1.2 时代常用重协商只对某些路径要求客户端证书。TLS 1.3 没有重协商,HTTP/2 下又不允许握手后认证(RFC 8740),也不是所有客户端都实现了它。应改为整个域名统一要求客户端证书,见双向 TLS。
  • 0-RTT 重放:打开早期数据却不在应用层做检查,重放的请求就会被执行。
  • 流量审计设备:老旧的 SSL 解密代理可能处理不了 TLS 1.3 或更大的后量子 ClientHello,真正的解决办法是升级设备。

TLS 1.0 和 1.1 应该早就关掉了:RFC 8996 在 2021 年 3 月正式废弃了这两个版本,RFC 9846 进一步禁止协商它们,主流浏览器在 2020 年前后已经移除。截至 2026 年 11 月,TLS 1.2 + 1.3 配合密码套件一文里的套件列表,是稳妥的默认配置。

常见问题

有了 TLS 1.3,可以关掉 TLS 1.2 吗?

大多数公网站点还不行。截至 2026 年 11 月,Mozilla 的 intermediate 配置仍保留 TLS 1.2(只用 ECDHE + AEAD 套件),照顾老手机、嵌入式设备和部分企业软件。客户端完全可控的 API 和内部服务可以只开 TLS 1.3。

0-RTT 能放心打开吗?

只适合可以安全重放的请求。攻击者截获 0-RTT 数据后可以重发,像支付这样的非幂等 POST 可能被执行两次。Nginx 的 ssl_early_data 默认关闭;如果打开,要把 $ssl_early_data 变量传给后端,对不安全的请求返回 425 Too Early(RFC 8470)。

配置里写了 TLSv1.3,为什么检测不到?

常见原因有三个:Web 服务器链接的是不支持 TLS 1.3 的旧版 OpenSSL(如 1.0.2);对外提供服务的其实是前面的 CDN 或云负载均衡,它们有自己的 TLS 策略;或者别的 server 块里的 ssl_protocols 覆盖了你的设置。用 nginx -V 看 OpenSSL 版本,再用 openssl s_client -tls1_3 从外部测试。

TLS 1.3 能隐藏访问的域名吗?

证书被加密了,但 ClientHello 的 SNI 扩展里域名仍是明文。基于 TLS 1.3 的 ECH(加密 ClientHello,RFC 9849)可以把 SNI 也加密,前提是站点在 DNS 里发布了 ECH 配置、客户端也支持。

资料来源

  1. RFC 9846: The Transport Layer Security (TLS) Protocol Version 1.3(2026 年 7 月)
  2. RFC 8446: TLS 1.3 最初版本(已被 RFC 9846 取代)
  3. RFC 8996: Deprecating TLS 1.0 and TLS 1.1
  4. RFC 8470: Using Early Data in HTTP
  5. RFC 10024: Post-Quantum Traditional (PQ/T) Hybrid Key Agreement Mechanisms for TLS 1.3
  6. RFC 9849: TLS Encrypted Client Hello
  7. nginx: Module ngx_http_ssl_module
  8. Mozilla wiki: Security/Server Side TLS