应用开发者需要了解的TLS早期数据(0RTT)安全风险
TLS 1.3代表了二十多年大规模传输安全部署经验的结晶。它在很大程度上简化并提升了TLS的安全性,可以作为TLS 1.2的直接替代品。然而,协议中的一个新功能对某些现有应用构成了重大安全风险:TLS 0-RTT(也称为早期数据)。这种性能优化可能导致未实现自身防重放防御的应用遭受重放攻击。在某些情况下,仅仅升级TLS依赖就可能引入应用级漏洞。
一个易受攻击的应用示例
假设您的公司运行一个带有买卖API的平台。由于各种遗留原因,公司使用API GET /api/sell/(item)/(qty) 和 GET /api/buy/(item)/(qty) 来实现这些操作。
当运维团队将TLS基础设施升级到支持TLS 1.3时,如果在CDN上启用、升级TLS硬件卸载盒或更新负载均衡器软件时启用了0-RTT,那么上述API现在就容易受到任意重放攻击。
攻击场景如下:用户登录系统后连接到咖啡店WiFi并发起买卖交易。由于TLS 1.3 0-RTT,该交易无需初始握手往返,节省了300ms!但攻击者可以捕获该请求并再次发送到服务器,与TLS 1.2不同,该请求不会被TLS层拒绝,买卖操作会再次执行。
什么是0-RTT?
TLS 0-RTT(“零往返时间"的缩写,正式名称为"TLS早期数据”)是一种降低TLS连接首字节时间的方法。当客户端和服务器拥有预共享密钥(PSK)时,客户端可以选择使用此密钥加密早期数据,并将其与ClientHello一起发送。这使得服务器可以在自己的ServerHello/EncryptedExtensions/Finished消息后立即响应请求的数据。
安全风险分析
0-RTT请求无法防止重放攻击。应用层需要从其TLS实现获取信息,以判断接收的请求是否为0-RTT。有了这些信息,应用程序可以通过拒绝非幂等操作上的0-RTT请求或通过直接的反重放防御(如nonce)来拒绝0-RTT。
解决方案建议
最重要的是升级到TLS 1.3!但在升级过程中,请禁用0-RTT,直到您能够审计应用程序是否存在此类漏洞。
- CDN环境:检查提供商文档,Cloudflare使用CF-0RTT-Unique头,应用程序需要跟踪该值并在非幂等端点上拒绝重复请求
- HAProxy:默认不启用0-RTT,可通过添加allow-0rtt启用,请求会带有Early-Data: 1头
- nginx:使用ssl_early_data on;启用,需要添加proxy_set_header Early-Data $ssl_early_data;
- Apache httpd:2.4.37及以上版本支持TLS 1.3,但目前无0-RTT支持
编程语言支持情况
- Go:1.12支持TLS 1.3,但无0-RTT支持
- Python:目前无早期数据支持
- Ruby:目前无早期数据支持
- C:可使用OpenSSL等库,通过SSL_CTX_set_max_early_data启用
最佳实践
- 升级到TLS 1.3但暂时禁用0-RTT
- 审计应用程序的重放攻击防护能力
- 为敏感操作实施强大的反重放防御
- 框架开发者应考虑提供API帮助管理此风险
密码学家正在研究如何在0-RTT请求中获得可用的前向安全性,但目前这仍是一个活跃的研究领域,尚无真正适合部署的解决方案。