应用开发者需要了解的TLS早期数据(0RTT)安全风险
TLS 1.3代表了二十多年大规模传输安全部署经验的结晶。它总体上简化并提升了TLS的安全性,可作为TLS 1.2的直接替代方案。然而,该协议中的一项新功能对某些现有应用构成了重大安全风险:TLS 0-RTT(也称为早期数据)。这种性能优化可能导致未实现自身防重放机制的应用遭受重放攻击。在某些情况下,仅升级TLS依赖就可能引入应用层漏洞。
易受攻击的应用示例
假设某公司运行一个具有买卖API的平台。由于历史遗留原因,公司通过GET /api/sell/(item)/(qty)和GET /api/buy/(item)/(qty) API实现这些操作。
当运维团队升级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设计存在两个关键问题:
- 缺乏前向安全性:由于PSK无需往返即可刷新,通过0-RTT发送的初始请求使用先前会话的密钥加密,不具备前向安全性
- 重放攻击风险:0-RTT请求无法防止重放攻击,需要应用层根据TLS实现提供的信息判断请求是否为0-RTT
RFC 8470尝试记录适用于0-RTT的缓解措施,但实现强大防御并非易事。目前Web应用通常不需要了解传输安全的细节,而针对此问题的解决方案仍有限。
防护措施建议
通用建议
- 升级到TLS 1.3,但在审计应用漏洞前禁用0-RTT
- 如果使用CDN进行TLS终止,查阅文档了解其提供的信息转发能力
- 确保对敏感操作实施强大的防重放机制
各环境具体配置
CDN环境:
Cloudflare使用CF-0RTT-Unique头,应用需要跟踪该值并在非幂等端点拒绝重复请求
HAProxy:
- 默认启用TLS 1.3不会启用0-RTT支持
- 在配置中添加
allow-0rtt启用0-RTT - 0-RTT请求通过
Early-Data: 1头代理到应用层 - 可通过返回425状态码拒绝请求
Nginx:
- 使用
ssl_early_data on;启用0-RTT - 添加
proxy_set_header Early-Data $ssl_early_data;确保头信息传递到应用
Apache httpd: 2.4.37及以上版本支持TLS 1.3,但目前(2019年3月)无0-RTT支持
开发框架建议
Web框架开发者应考虑提供API帮助用户管理此风险,同时保持性能优势。这可能需要与各种服务器合作制定通用API来代理所需信息。
直接使用TLS API
如果直接使用OpenSSL等TLS API,需要实现SSL_CTX_set_allow_early_data_cb等回调函数,并仔细考虑会话管理与重放保护的影响。
研究进展与未来方向
密码学家正在研究如何在0-RTT请求中实现可用的前向安全性。最新研究提出使用可穿刺伪随机函数显著减小会话数据库大小,但在计算复杂性和妥协后安全性方面存在权衡。这仍是活跃研究领域,尚无真正适合部署的解决方案。
常见问题解答
各语言支持情况(截至2019年3月):
- Go 1.12支持TLS 1.3但不支持0-RTT
- Python无早期数据支持
- Ruby无早期数据支持
- C应用可使用任何TLS栈,OpenSSL需调用
SSL_CTX_set_max_early_data启用0-RTT
如需在0-RTT世界中确保应用和用户安全的同时享受TLS 1.3的性能优势,建议咨询专业的安全工程和密码学团队。