TLS 协议基础回顾:握手、记录层、密码套件

说实话,做 DSPM 流量分析,绕不开 TLS。不管你是抓包调试,还是排查加密隧道里的异常,至少得把握手、记录层、密码套件这三个核心模块摸清楚。我早年第一次碰 TLS 流量分析时,就被那个加密握手绕晕过——后来才发现,只要把这三个东西拆开看,其实没那么复杂。

1. 握手协议:TLS 的“敲门砖”

握手协议负责在客户端和服务器之间协商加密参数、交换密钥、验证身份。我习惯把它看作一个“双向确认”的过程。TLS 1.2 和 1.3 的握手差别很大,但在实际 DSPM 环境中,两种版本都可能出现,所以我们得都懂。

1.1 TLS 1.2 经典握手(一次完整的 4 次握手)

客户端先发 ClientHello,带上支持的 TLS 版本、密码套件列表、随机数等。服务器回应 ServerHello,选定一个密码套件。接着服务器发证书(Certificate)和 ServerHelloDone。客户端验证证书,然后发 ClientKeyExchange(包含预主密钥的密文),最后双方各自计算出主密钥。再各自发 ChangeCipherSpec 和 Finished。嗯,这里要注意:ChangeCipherSpec 其实不属于握手协议,它是独立的记录层消息,但通常紧跟在握手之后。

我在项目中遇到过一个典型案例:某内部系统在迁移后 TLS 握手一直超时。抓包一看,服务端回复了 ServerHello 后突然断连。排查半天发现是客户端证书链太长,超过记录层 16KB 的片段上限。这种坑只有亲手拆过包才能踩到。

1.2 TLS 1.3 精简握手(1-RTT 为主)

TLS 1.3 把协商和密钥交换压缩到一次往返。客户端发 ClientHello 时直接带上密钥共享(如 ECDHE 参数),服务器收包后几乎能同时算出主密钥,再回复 ServerHello + 证书 + Finished。说白了,少了 ClientKeyExchange 和 ChangeCipherSpec 的显式步骤,效率高一大截。

不过,**DSPM 中分析 1.3 流量时有一个难点**:很多传统抓包工具对 1.3 的会话恢复(0-RTT)支持不好,导致你看不到完整的握手状态。我之前有一次就是因为抓包没抓到 0-RTT 的明文部分,误判为连接异常,后来才发现是工具版本太老。

1.3 握手过程中的关键字段(用于流量识别)

无论哪个版本,以下字段我们在 DSPM 分析时必须盯住:

  • 随机数(Random):每个握手唯一,可用于关联请求-响应。
  • 密码套件(Cipher Suite):决定了后续加密算法和安全等级。
  • 扩展(Extensions):SNI、ALPN、key_share 等,经常携带业务信息。
  • 证书链:可通过 OCSP Stapling 或 Certificate Status 验证吊销状态。

个人小技巧:抓包时我习惯先过滤 tls.handshake.type == 1(ClientHello),然后直接看 “Cipher Suites” 列表。如果列表里混着 TLS_NULL_WITH_NULL_NULL(0x0000),那基本上可以断定是不安全的配置——我扫到这类流量会直接标记为高危。

2. 记录层协议:TLS 的“运输容器”

所有 TLS 数据(握手、告警、应用数据)都装在记录层帧里。每个记录层帧包含 5 字节的头部,后面跟着可选的数据体,可能还被分片或拼接。

记录层头部结构很简单:

字节 0:    内容类型(Content Type,1 byte)
              0x20 = ChangeCipherSpec
              0x21 = Alert
              0x22 = Handshake
              0x23 = Application Data
字节 1-2:  协议版本(Major + Minor,2 bytes)
              例如 TLS 1.2 = 0x0303
字节 3-4:  数据长度(Length,2 bytes,大端)
              最大 2^14 = 16384 字节

举个例子,一个应用数据记录层的抓包原始字节可能是:17 03 03 05 00 ...,其中 17 表示 Application Data,03 03 表示 TLS 1.2,05 00 表示后面跟着 1280 字节加密数据。我在 DSPM 分析中常利用内容类型字段快速过滤:比如想只看握手消息就过滤 tls.record.content_type == 22。

注意:记录层有分片和重组问题。如果应用数据超过 16384 字节,发送方会拆成多个记录层帧。我记得有一次分析一个长连接流,应用层数据被拆成了 3 段,中间还夹杂了心跳记录。用 Wireshark 的“Follow TLS Stream”功能直接看原始复文,很容易漏掉中间分片——后来我改用 tshark 的 tls.segment 字段才把数据拼完整。

3. 密码套件:命名的算法组合

密码套件(Cipher Suite)本质上是一个由 4 个算法组成的组合:密钥交换算法 + 身份验证算法 + 加密算法 + MAC (HMAC) 算法。服务器从客户端提供的列表里选一个,后续所有加密通讯都按这个组合执行。

比如常见的 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:

  • ECDHE:密钥交换(椭圆曲线 Diffie-Hellman 临时密钥,提供前向安全性)
  • RSA:身份验证(用 RSA 签名验证证书)
  • AES_128_GCM:对称加密算法(128 位 AES,GCM 模式同时提供身份验证)
  • SHA256:HMAC 哈希(用于 Finished 消息等完整性校验,GCM 模式实际用 AEAD 自带认证,这里只是记录形式)

下表列出几个在 DSPM 环境中常见的密码套件和安全评级:

密码套件名称密钥交换加密认证安全等级
RSA_WITH_AES_128_CBC_SHARSAAES-128-CBCSHA-1⚠ 弱(无 PFS)
ECDHE_RSA_WITH_AES_128_GCM_SHA256ECDHEAES-128-GCMSHA-256✅ 强(PFS)
ECDHE_ECDSA_WITH_AES_256_GCM_SHA384ECDHEAES-256-GCMSHA-384✅ 强
DHE_RSA_WITH_CHACHA20_POLY1305_SHA256DHEChaCha20-Poly1305SHA-256✅ 强(移动端常见)
RSA_WITH_NULL_MD5RSA无MD5❌ 极危险(明文)

我曾经踩过的坑:有一次分析内部应用流量,发现加密通信被拦截后依然能解密。一查发现服务端竟然允许了 TLS_RSA_WITH_NULL_SHA(0x003B)——简单说就是没加密,只有签名。攻击者直接用 tcpdump 就能拿到明文数据。后来我在 DSPM 策略里加了一条规则:如果 ClientHello 中出现了任何包含 _NULL_ 的密码套件,直接告警。

4. 一张图串联三大模块

下面这张图展示了一个典型 TLS 1.2 握手中,记录层如何包裹握手消息,以及密码套件在哪个环节被确定。我把关键节点用不同颜色标出来,方便你快速记忆。

TLS 1.2 核心流程(握手 + 记录层 + 密码套件) 客户端 服务端 ClientHello(含密码套件列表) ServerHello(选定密码套件) 记录层封装: Certificate + ServerHelloDone ClientKeyExchange(预主密钥) ChangeCipherSpec + Finished ChangeCipherSpec + Finished 密码套件在 ServerHello 中选定

图中箭头方向表示消息流向。注意记录层对每个握手消息都加了 5 字节头(内容类型、版本、长度)。而密码套件的真正“拍板”发生在服务端回复 ServerHello 那一刻,后续的密钥生成全部依赖这个选定的组合。

5. 避坑指南:DSPM 中 TLS 协议分析的常见误解

最后,我根据自己的经验,总结几个容易踩的坑:

  1. 以为 TLS 版本可以直接从记录层版本字段读出来——实际上很多握手中记录层版本是“向下兼容”的,比如 TLS 1.2 的 ClientHello 可能把版本写成 0x0303,但后续记录层却变成 0x0301(TLS 1.0)。真正可靠的版本要看握手消息内部的版本协商。
  2. 忽略 ChangeCipherSpec 的独立性:ChangeCipherSpec 是一个独立的记录层内容类型(0x14),不是握手子消息。在 DSPM 自动化解析时,如果你把记录层内容类型和握手类型混在一起过滤,会漏掉这个切换点。
  3. 把密码套件名称中的算法顺序搞反:比如 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,_WITH_ 前面是密钥交换和认证,后面是加密和 MAC。新手经常把 GCM 当作认证算法,实际 GCM 只是加密模式,认证由 AEAD 内置提供。
  4. 重放攻击风险:即使使用了强密码套件,如果没有配合好随机数(尤其是客户端随机数),攻击者仍可能发起重放。我记得在一次安全审计中,发现某旧版实现使用了固定的客户端随机数,导致握手可被重放——这个在 DSPM 指纹检测中可以识别。

一句话总结本章:握手定身份和密钥,记录层封装所有通讯,密码套件是一切加密的“菜谱”。你把这三块吃透,看 TLS 流量就像看明文一样清晰。