摘要

  • 部分客户端遇到握手失败后,会用更低版本重新连接。在途攻击者只要阻断高版本尝试,就能影响下一次 ClientHello,而不必破解较新的 TLS。
  • POODLE 的明文恢复还需要 SSL 3.0 CBC、主动中间人、反复发送带秘密的请求以及篡改记录。原论文给出的期望工作量是每恢复 1 字节约 256 次请求。
  • TLS_FALLBACK_SCSV 不是密码套件。它只声明“这是降级重试”,让支持更高版本的服务器以 inappropriate_fallback(86) 在本地拒绝不必要的回退。

TLS 原本已有版本协商。客户端可以宣布 TLS 1.2,服务器若只支持 TLS 1.0,便选择双方共有的最高版本;协商结果进入受保护的握手过程。问题来自旁边那条为兼容旧服务器和旧中间设备而修出的捷径。

这条捷径把失败当作能力证明。第一次连接断掉,客户端便降低最高版本再试;继续失败,就继续下探,甚至抵达 SSL 3.0。但断线并不是服务器签名过的能力声明。处于路径上的攻击者可以制造同样的沉默。于是,攻击者无需击败 TLS 1.2,只需让客户端主动放弃它。

降级只是入口。真正泄露明文的是 SSL 3.0 的 CBC 记录保护。它允许填充中存在没有被 MAC 完整确定性覆盖的任意字节。原始 Web 攻击让浏览器重复发送携带 cookie 的 HTTPS 请求,把未知字节移动到块边界,再替换最后一个密文块,并根据服务器接受或拒绝来判断填充条件。

在论文描述的条件下,修改后的记录平均每 256 次被接受一次,因此每恢复一个字节的期望成本是 256 个 SSL 3.0 请求。这个数字不是统一速度,更不是保证耗时。攻击还需要在途位置、可塑造的请求、CBC 会话和大量重复。只看到服务器支持 SSL 3.0,并不能直接推导出 cookie 已经泄露。

最干净的处置是关闭 SSL 3.0。若历史依赖让立即关闭不可行,系统至少要分辨“对方真的只会旧版本”与“有人故意让新版本失败”。

RFC 7507 用一个很窄的信号解决这个问题。{0x56,0x00} 虽然放在 ClientHello 的套件列表中,却永远不能被服务器选为加密算法。它表示客户端正在用低于自身最高能力的版本重试。服务器拿收到的版本与自己的最高启用版本比较;若服务器能做得更好,就发送致命警报 86。

这里没有中央裁判。客户端说明重试状态,服务器依据本地配置拒绝不合理请求。但这个信号也不证明恶意:普通网络故障同样可能触发错误回退。RFC 7507 还明确说,SCSV 不能替代正常版本协商,也不能把只支持 SSL 3.0 的系统变安全。

控制随后完成了自己的历史使命。OpenSSL 在 1.0.1j、1.0.0o 和 0.9.8zc 中加入支持;RFC 7568 又明确禁止 SSL 3.0。到 RFC 8996,TLS 1.0 和 1.1 也被弃用,TLS 1.3 通过 ServerHello.Random 哨兵承担降级保护,RFC 7507 因而成为历史机制。

好的兼容设计不要求例外永生。它应让例外可识别、可拒绝、可观测,并最终可删除。