TLS 1.2 握手流程
TLS 1.2 的完整握手需要两次往返:客户端与服务端交换随机数、协商版本与套件,服务端下发证书(必要时发送密钥交换参数)并请求客户端证书,随后双方用密钥交换算法协商主密钥,切换加密后互相校验 Finished 消息。会话恢复时跳过证书与密钥交换步骤,握手缩短为一次往返。
基本信息
| 消息序列 | ClientHello → ServerHello → Certificate → ServerKeyExchange → ServerHelloDone → ClientKeyExchange → ChangeCipherSpec → Finished |
|---|---|
| 随机数 | ClientHello.random 与 ServerHello.random,参与密钥派生 |
| 密钥派生 | PreMasterSecret 经 PRF 得到 MasterSecret,再派生出会话密钥 |
| 双向认证 | 服务端请求客户端证书时增加 CertificateRequest 与 CertificateVerify |
| 会话恢复 | Session ID 或会话票据,跳过证书与密钥交换 |
| 扩展 | SNI、ALPN、OCSP Stapling 等随握手协商 |
典型使用场景
- 故障定位:握手失败时按消息序列逐段排查卡在哪一步
- 性能分析:确认是否命中会话恢复,判断延迟来源
- 兼容性测试:观察老客户端在哪个环节被拒绝
- 安全评估:确认是否协商到具备前向保密的密钥交换方式
- 抓包学习:理解 2-RTT 与 1-RTT 的差异
观察握手消息
观察握手消息
# -msg 打印握手消息,-state 打印状态变化,便于定位卡点
openssl s_client -connect example.com:443 -servername example.com -msg -state </dev/null 2>&1 | head -60
# 只看协议与套件结果
openssl s_client -connect example.com:443 -tls1_2 </dev/null 2>&1 | grep -E 'Protocol|Cipher'
# 抓包分析用过滤器限定端口,避免抓到无关流量
tcpdump -i eth0 -w handshake.pcap 'tcp port 443' -c 200关键消息作用
| 消息 | 方向 | 作用 |
|---|---|---|
| ClientHello | 客户端到服务端 | 携带随机数、可用套件、扩展与 SNI |
| ServerHello | 服务端到客户端 | 选定版本、套件与服务端随机数 |
| Certificate | 服务端到客户端 | 下发证书链,客户端据此验证身份 |
| ServerKeyExchange | 服务端到客户端 | ECDHE/DHE 场景下携带临时公钥与签名 |
| ClientKeyExchange | 客户端到服务端 | 携带密钥交换材料或加密后的预主密钥 |
| Finished | 双向 | 用协商密钥对握手记录做完整性校验 |
| ChangeCipherSpec | 双向 | 提示后续记录开始加密(1.3 中保留为兼容) |
握手失败时先确认服务端是否收到 ClientHello:完全无响应多与防火墙、端口或中间设备相关;有 ServerHello 之后失败则多为证书、套件或版本交集问题。证书链不完整时服务端日志往往没有记录,需要在客户端侧抓包或打印证书验证。
会话恢复会跳过证书与密钥交换消息,握手缩短为一次往返,这也是「首次访问慢、后续访问快」的原因之一。排查延迟问题时,先确认是否命中恢复,再判断瓶颈在网络还是服务端计算。