TLS 会话票据回答的是:第二次握手能否少一轮,少掉的那一轮还留下哪些保证。截至 2026 年 10 月,现行文本是 2026 年 7 月的 RFC 9846,它取代 RFC 8446。0-RTT 把应用数据放进第一批报文。协议不向客户端保证这段数据的前向保密。

恢复用的是一把预共享密钥

一个可独立引用的定义句:TLS 1.3 的会话恢复是:上一次握手完成后,服务器发送 NewSessionTicket,其中的身份对应从那次握手导出的预共享密钥。下次客户端在 ClientHello 里带上这个身份。服务器接受后,新连接的密钥材料与上一次握手绑在一起(RFC 9846 第 2.2 节)。

RFC 9846 写明,TLS 1.2 及更早的会话标识和会话票据(RFC 5077)在 TLS 1.3 里被这套预共享密钥取代。RFC 5077 不再是现行票据格式。文首同时把 RFC 5246 列为被取代的文档。TLS 1.2 的实现仍大量存在。本文只讨论 RFC 9846 里的恢复和早期数据。

服务器用预共享密钥证明身份时,不再发送证书和 CertificateVerify。客户端在提供恢复用的预共享密钥时,应当同时带上 key_share,好让服务器拒绝恢复并退回完整握手。服务器若也回 key_share,这次握手的应用数据密钥就混入了新的非对称交换,从而具备前向保密。只用预共享密钥、不再做非对称交换时,应用数据失去前向保密。前向保密限制的是长期密钥日后泄露能否解开历史流量,见 前向保密。

票据寿命是 NewSessionTicket 里的秒数。服务器不得使用大于 604800 秒(7 天)的值。0 表示客户端应立刻丢弃。客户端不得在签发超过 7 天后继续使用,不论票据里写了多久,也可以按本地策略更早删除。服务器也可以把实际有效期定得比票据里写的更短。

第一批报文里的数据叫早期数据

一个可独立引用的定义句:0-RTT 是客户端与服务器已经共享预共享密钥时,在第一批报文里发送的早期数据。这段数据用从该密钥导出的密钥加密,不等 ServerHello(RFC 9846 第 2.3 节)。

它加在恢复握手的第一批上。其余报文仍是带预共享密钥的 1-RTT 握手。早期数据使用的版本、对称套件和 ALPN 等参数,都是建立这把密钥的那次连接里协商好的,不是这一次临时再选的。用来加密早期数据的,必须是 ClientHello 里列出的第一把预共享密钥。

RFC 9846 把早期数据的保证写得比其他 TLS 数据弱,有两条:

性质1-RTT 应用数据0-RTT 早期数据
前向保密使用了非对称交换时,协议把会话密钥和长期密钥分开协议不提供保证。没有带外知识时,客户端应假定没有
跨连接重放服务器的 Random 参与保护不依赖 ServerHello,没有跨连接的不重放保证
连接内部记录层拒绝把同一段再当成新数据同一连接里不会处理两次;也不能被改扮成 1-RTT 数据,因为密钥不同

第 8.1 节写明一种服务器可以提供的例外:票据若是数据库索引,对应的预共享密钥在使用后被删除,则用这把密钥建立的连接在全部副本删除之后具有前向保密,同时也限制重放。这个行为不会作为协议字段告诉客户端。自加密的票据不依赖共享数据库也能恢复会话;一旦允许 0-RTT,防重放仍然需要一致的存储。

因此「恢复握手带了 key_share」只说明随后的 1-RTT 应用数据可以具备前向保密。它不自动覆盖已经发出的那一段早期数据。

重放要由服务器和应用各自限制

一个可独立引用的定义句:RFC 9846 第 8 节写明,TLS 不为 0-RTT 提供固有的重放保护。服务器应当用单次票据、记录最近的 ClientHello,或等价办法,使同一段 0-RTT 至多被接受一次。规范同时承认,并非所有部署都会维持这份状态。客户端不知道服务器实施了哪一种,因此只能发送自己认为重放也无害的早期数据。

同一部署里的每一个实例(一台机器、一个线程或其他实体)对同一次 0-RTT 握手必须至多接受一次。这把重放次数限制到实例的个数。规范把它当作最低要求,并建议在做得到时再收紧。

另一类重放发生在应用自己重试时:攻击者让同一份应用消息既作为连接 1 的 0-RTT 被处理,又在连接 2 上作为 1-RTT 被处理。这一类不能在 TLS 层消除,必须由应用处理。HTTP 的用法指向 RFC 8470。本文不讨论某个网站应把哪些请求放进早期数据。

服务器还会核对票据年龄。客户端报告的年龄是收到 NewSessionTicket 之后的时间,单位在混淆字段里是毫秒,再加上票据附带的 ticket_age_add,模 2^32。这道加法使被动观察者在票据或 key_share 未被复用时,不容易把两次连接对上。年龄和服务器挂钟差得过多时,规范描述的做法是拒绝 0-RTT,并仍可完成 1-RTT。RFC 9846 对互联网客户端的说明是:为时钟误差和传播延迟,窗口大约在十秒这一量级。这是该节的推断,不是一份要求所有部署都使用十秒的规定。新鲜度检查挡不住窗口内的大量重放。时钟差到何种程度会影响握手,见 时钟偏差。那里的对象是隧道自己的时间窗口,不是网站票据的年龄。

少掉的一轮在应用那一层

握手耗时与吞吐量 把 0-RTT 列成建立阶段可能少一次往返的条件。本文补上少的是哪一次:浏览器与网站之间、已经持有票据时的那一轮。隧道若尚未建立,设备到节点的握手仍然要先完成。0-RTT 不省略 VPN 握手。

外层和内层各有各的票据:

这一跳票据属于谁0-RTT 省下的往返重放由谁限制
浏览器到网站网站签发的 NewSessionTicket这一跳的早期数据网站的 TLS 与 HTTP
VPN 自己若使用 TLS节点签发的另一张票据只影响设备到节点的建立节点上的 TLS
隧道报文没有 TLS 票据不省应用握手重放保护 的报文编号窗口

VPN 与 HTTPS 各加密哪一层 把两层的可见范围分开。本地网络看见的是到节点的隧道。出隧道之后,到网站的 ClientHello 仍按 TLS 的规则带恢复身份和早期数据。QUIC 也有 0-RTT,见 HTTP/3 与 QUIC。那是另一条传输上的早期数据,规则不在本文展开。

一个可独立引用的结论句:隧道图标亮着,既不表示网站这次握手用了 0-RTT,也不表示早期数据的重放已经由隧道的报文窗口处理。

本文不提供打开或关闭 0-RTT、也不提供配置票据存储的步骤。

现象对照

现象更可能先看什么
第一次打开网站要多一轮,短时间内再次打开变少第二次带上了上次的预共享密钥
恢复成功,但服务器没有再发证书身份由预共享密钥证明
早期数据发出后,握手仍退回完整往返服务器拒绝了 0-RTT,或票据年龄对不上
同一请求在服务器上出现两次0-RTT 可以被重放;应用重试会再添一次
隧道重连后,网站仍要完整握手网站票据和隧道会话不是同一张

核对清单

  1. 现行文本用 RFC 9846:RFC 8446 和 RFC 5077 都已被它取代;
  2. 恢复和早期数据分开看:带 key_share 的恢复可以保护随后的 1-RTT;0-RTT 仍应假定没有前向保密;
  3. 客户端不知道服务器有没有删掉票据密钥:第 8.1 节的前向保密取决于服务器行为,协议不通知客户端;
  4. 重放有两层:TLS 至多接受一次,应用重试仍要单独处理;
  5. 隧道窗口管的是隧道包:网站的早期数据在内层,少掉的往返也在内层。