摘要

  • TLS 1.2 允许在已有连接中再次握手,却没有证明新的握手究竟延续了哪一次先前握手。
  • RFC 5746 保存上一次握手的客户端和服务器 verify_data,并在重协商时验证它们。

两次正确的握手,一段虚假的对话

攻击者先与服务器建立一条合法 TLS 连接,并发送自己选择的应用数据。随后,他把受害者的握手转发到这条已经受保护的连接上。受害者以为自己是在进行初始握手;服务器却可能把它看成攻击者连接上的一次重协商。

攻击者之后不能读取受害者的加密流量,但已经送达的前缀不会因此消失。服务器可能把攻击者选择的字节和受害者随后发送的、经过认证的数据看成同一段应用交互。在 HTTPS 中,如果应用没有明确区分认证前后的状态,这些前缀就可能与受害者之后提交的凭据或 Cookie 被联系起来。

问题不是密码算法失效,也不是证书被伪造。两次握手都可以有有效的 Finished 消息。缺少的是跨握手的连续性证明:新的握手没有说明自己是对方所见那次握手及其数据流的后继。

让上一次 Finished 成为连接状态

RFC 5746 增加了 secure_renegotiation 标志,并为每条连接保存上一次握手的客户端和服务器 verify_data。这些值属于当前连接,而不只是属于可能被恢复的会话缓存。

类型为 0xff01 的 renegotiation_info 扩展把这段历史带入下一次协商。初始握手中,renegotiated_connection 字段为空。重协商时,客户端发送保存的 client_verify_data;服务器将其与自己的状态比较,再返回客户端值和服务器值的拼接结果。客户端随后进行对应检查。缺少必需扩展,或数值不匹配,都会使握手以致命错误中止。

从解释角度看,协议因此改变了认证成功的含义:新的握手不仅要正确完成,还必须是这条具体连接历史的正确后继。

一个并非密码套件的兼容性代码

一些旧实现遇到未知扩展会失败。RFC 5746 因而定义了 TLS_EMPTY_RENEGOTIATION_INFO_SCSV,编码为 0x00,0xFF,并把它放入密码套件列表。旧实现本来就应忽略未知套件,这让客户端可以在不依赖可靠扩展解析器的情况下发出能力信号。

SCSV 不是可协商的密码套件,也不是后续重协商的绑定机制。它只服务于初始握手。若服务器没有确认安全重协商,客户端便无法同时保证最大兼容性和防止拼接攻击;TLS 本身也不能仅凭这一点区分服务器是有意拒绝重协商,还是根本没有修复。

从修复到移除

TLS 1.3 选择了不同的架构边界:禁止重协商。在 TLS 1.3 连接中稍后收到 ClientHello,应当作为意外消息处理。若旧版本连接在重协商中收到 TLS 1.3 的 ClientHello,它必须保留原协议版本,不能借重协商升级到 TLS 1.3。KeyUpdate 和握手后的认证仍然存在,但它们是不同的机制,不能统称为重协商。

对于 TLS 1.2,RFC 9325 要求客户端和服务器实现 renegotiation_info;服务器若不确认该扩展,客户端必须终止连接。RFC 5746 也不是所有多握手问题的答案;RFC 9325 另外要求使用扩展主密钥来应对相关的 triple-handshake 风险。它留下的历史意义更精确:时间连续性从应用的假设变成了经过认证的协议属性。

来源