TLS早期数据(0RTT)的安全风险与应对策略

本文深入解析TLS 1.3的0-RTT特性如何导致应用层重放攻击漏洞,通过实际案例展示风险成因,并提供CDN、HAProxy、Nginx等环境的解决方案和防护措施。

应用开发者必须了解的TLS早期数据(0RTT)风险

TLS 1.3代表了二十多年大规模传输安全部署经验的结晶。它主要简化和提升了TLS的安全性,可作为TLS 1.2的直接替代方案。然而,协议中的一项新功能对某些现有应用构成了重大安全风险:TLS 0-RTT(又称早期数据)。这种性能优化可能导致未实现自身防重放机制的应用遭受重放攻击。在某些情况下,仅升级TLS依赖就可能引入应用层漏洞。

一个易受攻击的应用程序案例

假设某公司运营一个具有买卖API的平台。由于历史遗留问题,公司使用GET /api/sell/(item)/(qty)GET /api/buy/(item)/(qty)实现这些操作。

当运维团队将TLS基础设施升级到支持TLS 1.3时(通过在CDN上启用、升级TLS硬件卸载设备或更新负载均衡器软件),如果启用了0-RTT功能,上述API将面临任意重放攻击风险。

攻击场景如下:

  1. 用户登录系统后连接咖啡店WiFi发起买卖请求
  2. 得益于TLS 1.3 0-RTT,交易无需初始握手往返,节省300ms
  3. 攻击者捕获该请求并重新发送给服务器
  4. 与TLS 1.2不同,该请求不会被TLS层拒绝,买卖操作会再次执行

什么是0-RTT?

TLS 0-RTT(零往返时间,官方称为"TLS早期数据")是一种降低TLS连接首字节时间的方法。当客户端和服务器拥有预共享密钥(PSK)时,客户端可以选择使用该密钥加密早期数据,并与ClientHello一起发送。这使得服务器可以在发送自己的ServerHello/EncryptedExtensions/Finished消息后立即响应请求数据,从而节省整个通信往返时间。

安全风险机制

0-RTT的主要安全问题包括:

  1. 缺乏前向安全性:0-RTT请求使用之前会话的密钥加密,不具备前向安全性
  2. 重放攻击风险:0-RTT请求无法防止重放攻击

应用层需要从TLS实现获取信息来判断接收的请求是否为0-RTT,然后通过以下方式防御:

  • 拒绝非幂等操作上的0-RTT请求
  • 使用nonce等直接防重放机制

解决方案

首要措施

  1. 升级到TLS 1.3,但暂时禁用0-RTT
  2. 审计应用程序是否存在此类漏洞
  3. 如果使用CDN进行TLS终止,查阅文档了解他们转发哪些信息

各平台配置指南

CDN环境

  • Cloudflare使用CF-0RTT-Unique头,应用需要跟踪该值并在非幂等端点拒绝重复请求

HAProxy

  • 默认不启用0-RTT
  • 可通过配置allow-0rtt启用,0-RTT请求会带有Early-Data: 1
  • 可通过返回425状态码拒绝请求

Nginx

  • 使用ssl_early_data on;启用
  • 需要添加proxy_set_header Early-Data $ssl_early_data;将头信息传递给应用

Apache httpd

  • 2.4.37及以上版本支持TLS 1.3,但目前(2019年3月)不支持0-RTT

编程语言支持情况

  • Go:1.12支持TLS 1.3,但不支持0-RTT
  • Python:目前无早期数据支持
  • Ruby:目前无早期数据支持
  • C:使用OpenSSL时,需调用SSL_CTX_set_max_early_data启用0-RTT,可使用SSL_CTX_set_allow_early_data_cb设置回调函数

研究进展

密码学家正在研究如何在0-RTT请求中实现可用的前向安全性。最新研究提出使用可穿刺伪随机函数来显著减小会话数据库大小,但这在计算复杂性和后妥协安全性方面存在权衡。目前这仍是一个活跃研究领域,尚无真正适合部署的解决方案。

如果您想在利用TLS 1.3性能优势的同时确保应用程序和用户在0-RTT环境中的安全性,请联系Trail of Bits的工程和密码学团队。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计