Session Ticket (会话票据)
定义
Session Ticket 是服务器交给客户端保管的加密会话状态,客户端下次连接时出示它即可恢复会话,服务器无需保存任何状态。
Session Ticket 最早由 RFC 5077 为 TLS 1.2 引入:握手结束后,服务器用只有自己知道的对称密钥(STEK,ticket 加密密钥)加密包括主密钥在内的会话状态,发给客户端;客户端重连时出示 ticket,服务器解密后即可恢复。TLS 1.3 沿用了这个名字:握手后服务器发送 NewSessionTicket 消息,每个 ticket 对应一个用于会话恢复的 PSK。
为什么重要
有了 ticket,大规模集群不需要共享会话缓存,只要每台服务器持有同一个 STEK 就能互相恢复会话。但 STEK 也正是薄弱环节:在 TLS 1.2 中,拿到 STEK 的人可以解密所有用它保护过 ticket 的历史会话,前向保密因此打了折扣。所以 ticket 密钥必须随机生成、不进备份和日志、安全分发并频繁轮换。如果无法保证轮换,一些加固指南建议对 TLS 1.2 关闭 ticket。
例子
openssl rand 80 > /etc/nginx/ticket.key # nginx 接受 80 或 48 字节的密钥文件
chmod 600 /etc/nginx/ticket.key
ssl_session_tickets on;
ssl_session_ticket_key /etc/nginx/ticket.current.key; # 用于加密新 ticket
ssl_session_ticket_key /etc/nginx/ticket.previous.key; # 仍可用于解密
配置多个密钥时,Nginx 只用第一个加密新 ticket,其余只用于解密,便于平滑轮换。
常见误区
- ticket 是用证书私钥加密的。 不是,用的是单独的对称密钥,与证书私钥无关。
- 续签证书会顺带轮换 ticket 密钥。 两者互不相关。证书换了多少次,长期不变的 STEK 依然有效,必须自己安排轮换。
- TLS 1.3 的 ticket 也有同样的前向保密问题。 使用 psk_dhe_ke 模式时,TLS 1.3 恢复会再做一次 ECDHE,泄露 ticket 密钥只会暴露 0-RTT 数据。