直接开启ssl_early_data on仅打开tls 1.3 0-rtt入口,真正实现“发包即响应”并安全落地,必须同步完成协议支持(ssl_protocols tlsv1.2 tlsv1.3)、会话复用(ssl_session_cache shared:ssl:10m)、请求筛选(limit_except get head拒绝非幂等操作)与后端协同(校验early-data头并拒非幂等操作),缺一不可,否则静默降级为1-rtt且暴露重放风险。

直接开启 ssl_early_data on 只是打开 TLS 1.3 0-RTT 的入口,真正实现“发包即响应”并安全落地,必须同步完成协议支持、会话复用、请求筛选与后端协同四件事——缺一不可,否则静默降级为 1-RTT,且重放风险完全暴露。
基础配置:让 0-RTT 跑起来的最小必要组合
以下配置必须全部出现在 HTTPS 的 server 块内(不能写在 http 或 location 中):
-
强制启用 TLS 1.3 并兼容老客户端:写
ssl_protocols TLSv1.2 TLSv1.3;——只写TLSv1.3会导致旧浏览器直连失败;但必须含TLSv1.3,否则无法生成 PSK,0-RTT 彻底失效 -
开启会话复用缓存:
ssl_session_cache shared:SSL:10m;和ssl_session_timeout 4h;——PSK 存储依赖此缓存,没它,客户端拿不到“票证”,0-RTT 自动退化 -
显式启用 early data:
ssl_early_data on;——仅该指令本身不生效,必须配合上述两项 -
提升协商成功率(尤其移动端):加
ssl_conf_command Options -PrioritizeChaCha;,因 ChaCha20-Poly1305 是 TLS 1.3 0-RTT 加密默认套件
前端请求控制:从路径和方法上堵住非幂等操作
Nginx 是第一道防线,不能把防重放全交给后端。对明确带副作用的接口,应在转发前就拦截:
- 对所有 API 写操作路径(如
/api/v1/order、/login),单独配location块,内部用limit_except GET HEAD { deny all; }直接拒绝 POST/PUT/DELETE 类请求进入 0-RTT 流程 - 静态资源(
/static/、/assets/)或公开只读接口(/status、/cities)可放开,允许走 0-RTT - 务必通过
proxy_set_header Early-Data $ssl_early_data;将标识透传给后端,避免后端靠猜测判断
后端安全决策:识别并拒绝高危操作
Nginx 不校验也不拦截重放,只负责传递信号。后端收到 Early-Data: 1 头后,必须立即执行:
- 若请求是 GET/HEAD 且无状态变更(如读取文章、获取用户公开资料、拉取字体文件),可直答,无需额外防护
- 若请求含任何写意图(登录、下单、转账、改密码、发消息),一律拒绝,返回
425 Too Early,强制客户端降级为 1-RTT 重发 - 极少数必须支持 0-RTT 写的场景(如实时投票),需叠加三要素防护:一次性 token + ≤5 秒时间戳窗口 + 请求指纹(body hash + client IP + UA 哈希),三者缺一不可
验证是否真生效:别信配置,要抓包看行为
光配对不等于跑通。建议交叉验证:
- 用 Wireshark 抓包,确认 ClientHello 扩展中含
early_data,且 ServerHello 后立刻出现加密的 Application Data(中间无等待客户端 Finished) - 在 Nginx 日志中添加
$ssl_early_data变量,观察高频访问用户是否稳定输出1 - 用 curl 测试:
curl -vkI --http2 https://your.site/,结合日志与响应头比对,确认 0-RTT 是否被识别和处理











