2. TLS 握手全流程详解

TLS 握手,说白了就是客户端和服务器在正式通信前互相“验明正身”并商量好加密参数的环节。我入行那会儿觉得这步就是走个过场,直到在抓包时发现有人伪造服务端证书 — 嗯,从那以后我再也不敢轻视握手了。

2.1 ClientHello — 客户端发起招呼

握手的第一步,客户端发送 ClientHello 消息。里面包含了什么?

  • 版本号:比如 TLS 1.2、TLS 1.3
  • 随机数:32 字节,用于后续密钥生成
  • 会话 ID:如果之前有会话可以复用
  • 密码套件列表:客户端支持的加密算法组合
  • 扩展字段:SNI、ALPN、Key Share(TLS 1.3)等
个人经验:我建议重点检查 ClientHello 中的密码套件列表。如果出现不常见的弱套件,很可能是有意降级攻击。

2.2 ServerHello — 服务器回应选择

服务器收到 ClientHello 后,从中挑选一套双方都支持的参数,发回 ServerHello。内容类似:

  • 最终选用的协议版本
  • 服务端随机数
  • 选定的密码套件
  • 可选的压缩方法(实际很少用)

这里有个坑:如果服务器选择的版本比客户端低,可能是中间人降级攻击。我记得有一次排查延迟问题,抓包发现服务器莫名其妙选了 TLS 1.0,后来发现是负载均衡器配置错误。

2.3 证书交换 — 身份证明

Certificate 消息:服务器把自己的证书链发给客户端,有时也会请求客户端证书(双向认证)。证书里包含公钥、签发者、有效期等信息。

我习惯用 OpenSSL 检查证书链完整性:

openssl s_client -connect example.com:443 -showcerts 2>/dev/null | openssl x509 -text -noout

如果证书链不完整或自签名,客户端通常会报错。但很多恶意软件会忽略验证,直接信任任意证书。这就是检测异常的好时机。

2.4 密钥协商 — 悄悄生成共同密钥

证书验证通过后,客户端和服务器需要协商出一个对称密钥。常见方式:

方式 说明 典型场景
RSA 密钥交换 客户端用服务器公钥加密预主密钥,服务器私钥解密 TLS 1.2 及之前,但不提供前向安全
Diffie-Hellman (DHE/ECDHE) 双方交换 DH 参数,各自计算共享密钥 现代 TLS 推荐,提供前向安全

我记得项目经理曾问:为什么 ECDHE 比 RSA 慢?其实只是握手阶段多算两次椭圆曲线乘法,对整个连接的影响几乎可以忽略,换来的是每次会话密钥独立,窃听后也无法解密之前的数据。

客户端发送 ClientKeyExchange(携带 DH 公钥或加密的预主密钥),然后双方各自计算主密钥,再派生出会话密钥。

注意:密钥协商阶段如果发现预主密钥长度不符合预期(比如 RSA 密钥交换时只有 32 字节),几乎可以判定是恶意篡改。

2.5 Finished 消息 — 握手完整性校验

双方都发送 ChangeCipherSpec(通知后续使用新密钥),紧接着发送 Finished。Finished 是对整个握手消息的 HMAC 摘要,用协商的密钥加密。如果双方校验一致,握手成功;否则连接断开。

这是一个强有力的检测点 — 如果 Finished 消息验证失败,说明握手过程中的某个消息被修改过。我曾经在渗透测试中伪造过 ClientHello 的扩展字段,结果服务端 Finished 直接拒绝,让我花了半天才定位到问题。

2.6 完整握手流程

下面这张图展示了 TLS 1.2 全握手的过程(忽略 Session Ticket 等优化细节):

TLS 1.2 全握手流程 客户端 服务器 ClientHello ServerHello + Certificate + ServerHelloDone ClientKeyExchange + ChangeCipherSpec + Finished ChangeCipherSpec + Finished ① 打招呼(ClientHello / ServerHello) ② 证书交换(Certificate) ③ 密钥协商(Key Exchange) ④ 握手完成(Finished) ⚠ 异常检测关键点 • ClientHello 中的密码套件列表:是否包含弱套件? • ServerHello 中的版本:是否被降级? • Certificate 链:是否自签、过期、伪造? • Finished 校验:任意一方失败意味着握手被篡改。

2.7 异常检测切入点总结

我把常见的异常行为整理成了一张表,方便你在抓包时快速对照:

阶段 正常表现 异常信号
ClientHello 密码套件列表约 10-30 个,版本号合理 列表仅含 1-2 个弱套件,或版本号过低
ServerHello 选择主流套件,版本匹配 选择不常见套件,或版本低于客户端
Certificate 证书链完整,有效期正常 自签名、过期、域名不匹配、链不完整
Key Exchange 预主密钥或 DH 参数符合协议规范 长度异常、值重复、使用非标准的椭圆曲线
Finished 双方校验通过,握手立即完成 校验失败、Finished 消息缺失或乱序
核心思路:TLS 握手是高度结构化的协议。任何偏离标准流程的细微异常,都值得深挖。比如一个 ClientHello 中同时出现 SSL 3.0 和 TLS 1.3 的密码套件,基本可以断定不是正常浏览器发出的。

学会了握手细节,下一层就是把这些异常行为自动化检测。当然,那是后面课程的内容了。如果你现在就想动手,可以先装个 Wireshark,抓一次正常的 HTTPS 连接,对照上面的表逐条验证。我自己就是这么练出来的。