1. TLS握手基础:协议概述、握手过程、密码套件协商

1.1 TLS协议概述

TLS(传输层安全)说白了就是在 TCP 上面罩一层加密壳。你浏览器访问 HTTPS 网站时,背后就是这个协议在干活。我当年刚入行时,觉得 TLS 就是个加密通道,后来被一个重放攻击搞到凌晨三点才明白——它远不止加密那么简单。

TLS 的核心目标有三个:

  • 机密性 — 数据只有通信双方能看懂,中间人拿到的全是乱码。
  • 完整性 — 任何篡改都能被检测出来,哪怕改一个比特。
  • 身份认证 — 至少服务器身份是可信的(客户端可选)。

嗯,这里要注意:TLS 本身并不防 DDoS,也不防应用层漏洞。它只解决传输链路的安全问题。你想想看,如果应用本身有 SQL 注入,TLS 也救不了你。

一张图总结 TLS 在协议栈中的位置:
应用层(HTTP/FTP/SMTP) → TLS 层 → TCP 层 → IP 层

1.2 握手过程

握手是整个 TLS 最复杂的阶段。我建议你把它拆成四个阶段来理解:

  1. 阶段一:Hello 交换 — 客户端和服务端互相打招呼,协商版本、密码套件、随机数。
  2. 阶段二:认证与密钥交换 — 服务端发送证书(或密钥交换参数),客户端验证。
  3. 阶段三:密钥计算 — 双方用 Premaster Secret 和随机数派生出会话密钥。
  4. 阶段四:握手结束 — 发送 Change Cipher Spec 和 Finished 消息,确认握手完成。

下面这张 SVG 图展示了完整的握手流程(以最常见的 TLS 1.2 为例)。注意箭头方向和数据内容——我在项目中排查过不少握手失败的案例,每次都要对着这张图逐条核对。

TLS 1.2 完整握手流程 客户端 服务端 ClientHello ServerHello Certificate ServerHelloDone ClientKeyExchange ChangeCipherSpec Finished 支持的版本、密码套件、随机数 选定版本、密码套件、随机数 服务器证书(含公钥) 用公钥加密的 Premaster Secret 通知:后续消息将加密 已加密的握手消息校验 握手完成后,双方用会话密钥加密应用数据
避坑提醒: 我曾经遇到过一个案例——服务端发了 Certificate 但客户端一直报证书链错误。最后发现是中间证书缺失,导致验证链断裂。所以抓包时一定要检查 Certificate 消息里的证书链是否完整。

1.3 密码套件协商

密码套件,说白了就是一组加密算法的组合。客户端在 ClientHello 里列出一堆自己支持的,服务端挑一个它觉得最合适的。我个人的习惯是把密码套件拆成四个部分来看:

组成部分示例 (TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256)作用
密钥交换算法ECDHE协商 Pre-master Secret,实现前向安全
身份认证算法RSA验证证书签名,确认对方身份
对称加密算法 + 模式AES_128_GCM加密实际传输的数据
HMAC / AEAD 认证SHA256 (GCM自带认证)保证数据完整性

这里有个重点:前向安全。你想想看,如果攻击者今天把你服务器的私钥偷了,他能不能解密几年前录下来的流量?答案是——如果用的是 ECDHE/RSA 这种静态密钥交换,他就能解;但如果用了 DHE 或 ECDHE(临时密钥),私钥泄漏也不会影响过去会话。这也是为什么现代 TLS 都推荐 ECDHE 的原因。

我的一个小技巧: 抓包分析异常握手时,先看 ClientHello 里的密码套件列表顺序。服务端通常会选客户端列出的第一个它支持的套件。如果客户端首选是个弱算法(比如 RC4),那很可能是老旧客户端或者恶意降级攻击。我曾在某金融系统抓包中看到客户端把 TLS_RSA_WITH_RC4_128_SHA 排在第一位——尽管系统版本是 2018 年的,明显有问题。

除了算法组合,还有一个常被忽视的细节:密码套件与 TLS 版本的关系。例如 TLS 1.3 废弃了大部分 RSA 和 CBC 模式的套件,只保留 AEAD 类(如 GCM 和 ChaCha20-Poly1305)。所以如果看到 TLS 1.3 的握手里出现 CBC 套件,那肯定是伪造的——直接标红。

小结

这一章我们摸了 TLS 握手的基础。协议概述帮你定位 TLS 在整个网络栈里的角色;握手过程给了你一张能对着抓包结果逐行对照的流程图;密码套件协商则告诉你怎么读懂 ClientHello 和 ServerHello 里面的关键参数。后面几章我们会把这些基础用到实际异常模式识别里——到时候你会发现,很多奇怪现象其实在握手阶段就已经有苗头了。