TLS 1.3 握手过程动画级讲解 + Wireshark 验证

📅 2026/7/14 8:58:47 👁️ 阅读次数 📝 编程学习
TLS 1.3 握手过程动画级讲解 + Wireshark 验证

文章目录

    • 一、为什么必须单独学 TLS 1.3?
    • 二、TLS 记录层与握手消息总览
      • 2.1 四层封装(复习)
      • 2.2 TLS 1.3 完整握手「一图流」
    • 三、动画级分帧:ClientHello(帧 ①)
      • 3.1 客户端发出什么?
      • 3.2 关键扩展详解
      • 3.3 「动画」:客户端在想什么
    • 四、动画级分帧:ServerHello(帧 ②)
      • 4.1 服务器选择参数
      • 4.2 密钥派生(概念动画)
      • 4.3 「动画」:服务器侧
    • 五、动画级分帧:加密握手段(帧 ③④)
      • 5.1 EncryptedExtensions
      • 5.2 Certificate + CertificateVerify
      • 5.3 Finished
      • 5.4 握手完成状态机
    • 六、TLS 1.3 套件与算法(安全视角)
      • 6.1 仅 AEAD 套件
      • 6.2 密钥交换组
    • 七、0-RTT 与会话恢复(动画补充)
      • 7.1 1-RTT 恢复(PSK)
      • 7.2 0-RTT Early Data
      • 7.3 Wireshark 识别
    • 八、实验环境
      • 8.1 拓扑
      • 8.2 nginx 启用 TLS 1.3
      • 8.3 确认 OpenSSL 与 curl 支持
    • 九、Wireshark 抓包与解密配置
      • 9.1 抓包
      • 9.2 SSLKEYLOGFILE(推荐)
      • 9.3 强制完整握手(避免 PSK 干扰观察)
    • 十、Wireshark 逐包验证清单
      • 10.1 第一包:ClientHello
      • 10.2 第二包:ServerHello
      • 10.3 加密握手段
      • 10.4 应用数据
      • 10.5 对照实验记录表(实验报告模板)
    • 十一、TLS 1.2 vs 1.3:同屏对比实验
      • 11.1 强制 TLS 1.2 抓一包
      • 11.2 动画对比
    • 十二、降级攻击与 Middlebox 兼容
      • 12.1 为何 ClientHello 写 TLS 1.2?
      • 12.2 降级攻击防护
      • 12.3 测试服务器最低版本
    • 十三、常见踩坑
    • 十四、安全加固建议(运维向)
    • 十五、与攻击链的关联
    • 十六、完整实验步骤(90 分钟)
    • 十七、本篇小结
    • 附录 A:Wireshark 过滤器速查
    • 附录 B:openssl 调试命令
    • 附录 C:握手消息类型编号
    • 附录 D:与专栏前篇关联

定位:网络基础与协议安全篇 · 把 TLS 1.3 握手机制「逐帧看懂」
声明:抓包与密钥日志实验仅限自有靶场或授权环境;勿对未授权流量解密分析。


一、为什么必须单独学 TLS 1.3?

上一篇讲了 HTTPS 抓包与解密,但TLS 1.2 与 1.3 握手差异巨大

对比项TLS 1.2TLS 1.3
完整握手 RTT2-RTT(常见)1-RTT
恢复会话Session ID / TicketPSK + 0-RTT
密钥交换RSA、DHE、ECDHE 混用仅 ECDHE/DHE(前向保密)
证书发送时机ServerHello 后明文ServerHello 后加密
废弃算法仍可能见到RC4、3DES、EXPORT、RSA 密钥传输等移除
中间人可见更多握手明文仅 ClientHello / ServerHello 主体可见

不懂 1.3,Wireshark 里会出现「Server Hello 之后全 Application Data」的断层,误以为是抓包坏了。本文用动画级分帧图 + 逐字段对照,在靶场里一次验证通过。


二、TLS 记录层与握手消息总览

2.1 四层封装(复习)

┌──────────────────────────────────────┐ │ HTTP / HTTP/2 应用数据 │ ├──────────────────────────────────────┤ │ TLS 记录层(Content Type + 密文) │ ← 本文重点 ├──────────────────────────────────────┤ │ TCP │ ├──────────────────────────────────────┤ │ IP │ └──────────────────────────────────────┘

Content Type(记录层类型):

含义TLS 1.3 说明
22HandshakeClientHello、ServerHello 等
23Application Data加密后的 HTTP
20ChangeCipherSpec1.3 中通常不出现(兼容旧栈时可能有)
21Alert警告/关闭

2.2 TLS 1.3 完整握手「一图流」

时间 → 客户端 服务器 │ │ │════════ ClientHello ══════════════════════════════►│ ① 明文 │ 版本、套件、key_share、SNI、supported_versions │ │ │ │◄════════ ServerHello ═════════════════════════════│ ② 明文 │◄──────── {EncryptedExtensions} ────────────────────│ ③ 起加密 │◄──────── {Certificate} ──────────────────────────│ │◄──────── {CertificateVerify} ────────────────────│ │◄──────── {Finished} ─────────────────────────────│ │ │ │──────── {Finished} ───────────────────────────────►│ ④ 客户端确认 │ │ │════════ Application Data (HTTP) ═════════════════►│ ⑤ 应用数据 │◄════════ Application Data ═══════════════════════│

大括号{ }表示使用握手流量密钥(Handshake Traffic Secret)加密,Wireshark 配好密钥后可展开。


三、动画级分帧:ClientHello(帧 ①)

3.1 客户端发出什么?

[帧 ①] ClientHello ┌─────────────────────────────────────────┐ │ Handshake Type: Client Hello (1) │ │ Legacy Version: 0x0303 (TLS 1.2 伪装) │ ← 兼容中间盒 │ Random: 32 字节客户端随机数 │ │ Session ID: 空或 PSK 会话标识 │ │ Cipher Suites: TLS_AES_128_GCM... 等 │ │ Compression: null (0) │ │ Extensions: │ │ ├─ server_name (SNI) │ │ ├─ supported_versions (真正声明 1.3) │ │ ├─ supported_groups (x25519 等) │ │ ├─ key_share (客户端 ECDHE 公钥) │ ← 1.3 核心 │ ├─ signature_algorithms │ │ ├─ psk_key_exchange_modes (可选) │ │ └─ ... │ └─────────────────────────────────────────┘

3.2 关键扩展详解

扩展作用安全意义
supported_versions声明支持 TLS 1.3真正版本协商处,Legacy Version 常为 0x0303
key_share客户端临时 ECDHE 公钥1-RTT 密钥材料,前向保密
server_name (SNI)目标域名仍明文,虚拟主机必备
signature_algorithms签名哈希算法列表验证书链用
psk_key_exchange_modesPSK 模式为 0-RTT / 会话恢复铺路

3.3 「动画」:客户端在想什么

T+0ms 用户输入 https://lab.local T+1ms DNS 解析 → TCP SYN → SYN-ACK → ACK T+5ms 构造 ClientHello: · 我支持 TLS 1.3 · 我选 x25519,公钥是 [ClientPubKey] · 我要去的服务器名叫 lab.local T+6ms 发出 ClientHello ───────────────►

四、动画级分帧:ServerHello(帧 ②)

4.1 服务器选择参数

[帧 ②] ServerHello ┌─────────────────────────────────────────┐ │ Handshake Type: Server Hello (2) │ │ Legacy Version: 0x0303 │ │ Random: 32 字节(末 8 字节有特殊含义*) │ │ Session ID: ... │ │ Cipher Suite: TLS_AES_256_GCM_SHA384 │ ← 选定套件 │ Extensions: │ │ ├─ supported_versions: TLS 1.3 (0x0304)│ │ └─ key_share: x25519 [ServerPubKey] │ ← 服务端临时公钥 └─────────────────────────────────────────┘ * 若协商 TLS 1.3,Random 最后 8 字节固定为特殊模式,便于区分降级攻击 (Wireshark 中可见 "TLS 1.3" 标注)

4.2 密钥派生(概念动画)

ClientHello.key_share + ServerHello.key_share ↓ ECDH 运算 Shared Secret(共享秘密) ↓ HKDF 扩展 Handshake Traffic Secret(握手期密钥) ↓ 加密后续握手消息 {Certificate} {Finished} ... ↓ 双方 Finished 完成 Application Traffic Secret(应用期密钥) ↓ HTTP 密文双向流动

前向保密(PFS):临时 ECDHE 私钥会话结束即丢弃,历史抓包无法用长期私钥解密——这也是上一篇「拿 nginx 私钥解 ECDHE 流量失败」的原因。

4.3 「动画」:服务器侧

T+20ms 收到 ClientHello T+22ms 选择 TLS_AES_256_GCM_SHA384 + x25519 T+23ms 生成 ServerPubKey,计算 Shared Secret T+24ms 派生 Handshake Traffic Secret T+25ms 发出 ServerHello ──────────────► T+26ms 同 TCP 段或紧随其后发出加密的: EncryptedExtensions + Certificate + CertificateVerify + Finished

1-RTT 含义:客户端发完 ClientHello,等一轮服务器响应后,双方已可推导出应用密钥(客户端还需发 Finished,但应用数据可紧跟)。


五、动画级分帧:加密握手段(帧 ③④)

5.1 EncryptedExtensions

[帧 ③a] {EncryptedExtensions} ┌─────────────────────────────────────────┐ │ 解密后常见扩展: │ │ ├─ application_layer_protocol_negotiation (ALPN: h2 / http/1.1) │ ├─ max_fragment_length │ └─ server_name 相关确认(较少) │ └─────────────────────────────────────────┘

ALPN决定走 HTTP/2 还是 HTTP/1.1,解密后 Wireshark 会显示h2http

5.2 Certificate + CertificateVerify

[帧 ③b] {Certificate} 服务器证书链(叶子 + 中间 CA) [帧 ③c] {CertificateVerify} 服务器用私钥对「至今所有握手 transcript」签名 证明:持有证书对应私钥的人参与了本次握手

5.3 Finished

[帧 ③d] {Finished} (服务端) 对完整握手 transcript 的 MAC,证明握手未被篡改 [帧 ④] {Finished} (客户端)──► 客户端同样确认 transcript

5.4 握手完成状态机

ClientHello │ ▼ ServerHello ──► 双方有 Handshake Secret │ ▼ 加密段到达 + 解密成功 │ ▼ Client Finished ──► Application Secret 就绪 │ ▼ Application Data(HTTP)

六、TLS 1.3 套件与算法(安全视角)

6.1 仅 AEAD 套件

TLS 1.3 标准化套件示例:

套件名加密哈希
TLS_AES_128_GCM_SHA256AES-128-GCMSHA256
TLS_AES_256_GCM_SHA384AES-256-GCMSHA384
TLS_CHACHA20_POLY1305_SHA256ChaCha20-Poly1305SHA256

不再有TLS_RSA_WITH_AES_...这类 RSA 密钥传输套件。

6.2 密钥交换组

说明
x25519最常用,速度快
secp256r1 (P-256)NIST 曲线
secp384r1更高强度

蓝队检查:禁用弱曲线、强制 TLS 1.3-only(视业务兼容性)。


七、0-RTT 与会话恢复(动画补充)

7.1 1-RTT 恢复(PSK)

老用户第二次访问:

客户端 服务器 │ │ │ ClientHello │ │ + pre_shared_key (PSK identity + binder) │ │ + key_share (可选,用于 PFS 混合模式) │ ├───────────────────────────────────────────────────►│ │◄ ServerHello + {EncryptedExtensions} │ │◄ {Finished} │ │ {Finished} ───────────────────────────────────────►│ │ Application Data ═════════════════════════════════►│

Binder:证明 ClientHello 未被篡改,防 PSK 重放。

7.2 0-RTT Early Data

客户端 服务器 │ │ │ ClientHello + Early Data (HTTP GET 已加密发出) │ ├───────────────────────────────────────────────────►│ │◄ ServerHello + ... │
优点风险
省 1 RTT,首包更快Early Data无前向保密
适合 CDN、重复 GET重放攻击:攻击者可重放 0-RTT 请求

防御:服务器对 0-RTT 请求只放行幂等操作(安全策略严格时直接禁用 0-RTT)。

7.3 Wireshark 识别

tls.handshake.extensions.early_data tls.handshake.extensions.pre_shared_key

八、实验环境

8.1 拓扑

受害机 / Web 192.168.56.30 nginx + TLS 1.3 分析机 Kali 或本机 Wireshark 4.x+ 测试客户端 同网段浏览器或 curl

8.2 nginx 启用 TLS 1.3

# Ubuntu 22.04+ / 较新 OpenSSLsudoaptinstall-ynginx opensslsudotee/etc/nginx/snippets/tls13.conf<<'EOF' ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:TLS_AES_256_GCM_SHA384; ssl_prefer_server_ciphers off; EOF# 在 443 server 块 include snippets/tls13.confsudonginx-t&&sudosystemctl reload nginx# 验证echo|openssl s_client-connect192.168.56.30:443-tls1_32>/dev/null|grepProtocol# 应见 Protocol : TLSv1.3

8.3 确认 OpenSSL 与 curl 支持

openssl version# 1.1.1+ 支持 TLS 1.3curl--tlsv1.3-vkhttps://192.168.56.30/

九、Wireshark 抓包与解密配置

9.1 抓包

# 在 Web 服务器或 Kali 镜像口sudowireshark-ieth1-f"host 192.168.56.30 and tcp port 443"

另开终端触发握手(每次测试新开隐私窗口,避免会话恢复干扰):

curl--tlsv1.3-vkhttps://192.168.56.30/-o/dev/null

9.2 SSLKEYLOGFILE(推荐)

exportSSLKEYLOGFILE=/tmp/tls13.keys.log chromium https://192.168.56.30/# 或 Chrome# Wireshark → Edit → Preferences → Protocols → TLS# (Pre)-Master-Secret log filename → /tmp/tls13.keys.log

重新加载抓包文件后,加密握手段与 Application Data 应可解密。

9.3 强制完整握手(避免 PSK 干扰观察)

· 浏览器隐私模式 · curl 每次新连接:curl --tlsv1.3 --no-sessionid · 服务器侧重载 nginx 清空 ticket(靶场)

十、Wireshark 逐包验证清单

10.1 第一包:ClientHello

过滤器:

tls.handshake.type == 1

核对表:

字段期望
Handshake TypeClient Hello (1)
Version (Legacy)0x0303
Extension: supported_versions包含 TLS 1.3 (0x0304)
Extension: key_share含 x25519 与公钥长度 32 字节
Extension: server_name你的域名或 IP
Cipher Suites含 TLS_AES_128_GCM_SHA256 等

展开路径示例:

Transport Layer Security └─ TLSv1.3 Record Layer: Handshake Protocol: Client Hello └─ Extension: supported_versions (TLS 1.3) └─ Extension: key_share (x25519)

10.2 第二包:ServerHello

tls.handshake.type == 2
字段期望
supported_versionsTLS 1.3选中
Cipher SuiteTLS_AES_256_GCM_SHA384 等
key_share服务端 x25519 公钥

10.3 加密握手段

解密成功后,同一 TCP 流中应看到:

Handshake Protocol: Encrypted Extensions Handshake Protocol: Certificate Handshake Protocol: Certificate Verify Handshake Protocol: Finished

过滤器(解密后):

tls.handshake.type == 8 # Encrypted Extensions tls.handshake.type == 11 # Certificate tls.handshake.type == 15 # Certificate Verify tls.handshake.type == 20 # Finished

10.4 应用数据

http || http2

或:

tls.record.content_type == 23

Follow → HTTP/2 Stream 或 HTTP Stream,看到GET /即全链路打通。

10.5 对照实验记录表(实验报告模板)

序号消息明文/加密关键字段截图编号
1ClientHello明文supported_versions, key_share, SNIfig-01
2ServerHello明文选定套件、Server key_sharefig-02
3EncryptedExtensions加密ALPN = h2/http1.1fig-03
4Certificate加密颁发者、SANfig-04
5Finished ×2加密握手完成fig-05
6Application Data加密→解密GET 请求fig-06

十一、TLS 1.2 vs 1.3:同屏对比实验

11.1 强制 TLS 1.2 抓一包

curl--tlsv1.2-vkhttps://192.168.56.30/-o/dev/null
现象TLS 1.2TLS 1.3
ServerHello 后常有Certificate 明文Certificate在加密块内
密钥交换ServerKeyExchange / ClientKeyExchange 可能单独出现合并进 key_share
报文数量通常更多更少、更紧凑
ChangeCipherSpec常见通常无

过滤器对比:

tls.handshake.type == 11 && frame.number < 50

1.2 往往在早期帧即可见 Certificate;1.3 需解密后才见。

11.2 动画对比

TLS 1.2(简化): C: ClientHello ──────► S: ServerHello ───────► S: Certificate ───────► 明文 S: ServerHelloDone ───► C: ClientKeyExchange ─► C: ChangeCipherSpec ──► C: Finished ──────────► S: ChangeCipherSpec ──► S: Finished ──────────► ══ Application Data ══ TLS 1.3: C: ClientHello ──────► S: ServerHello + {Cert+Finished...} ──► C: {Finished} ───────► ══ Application Data ══

十二、降级攻击与 Middlebox 兼容

12.1 为何 ClientHello 写 TLS 1.2?

部分老旧防火墙见到「非 0x0303」就丢包。客户端在Legacy Record Layer写 0x0303,在supported_versions扩展里声明 1.3。

12.2 降级攻击防护

TLS 1.3 在 ServerHello Random 嵌入特殊标记;Finished 覆盖完整 transcript。
蓝队:禁用服务器 TLS 1.0/1.1/1.2,可减攻击面(需评估业务)。

12.3 测试服务器最低版本

# 应失败(若仅允许 1.2+)openssl s_client-connect192.168.56.30:443-tls1# 应成功openssl s_client-connect192.168.56.30:443-tls1_3

十三、常见踩坑

问题原因解决
看不到 TLS 1.3OpenSSL/nginx 过旧升级;检查ssl_protocols
ServerHello 后「断层」1.3 握手加密配置 SSLKEYLOGFILE
一直是 Session Ticket 恢复浏览器缓存 PSK隐私窗口 /--no-sessionid
Wireshark 显示 TLS 1.2仅看 Legacy Versionsupported_versions扩展
解密后无 Certificate解密失败或走 1.2检查 key log 路径、重抓
curl 无 1.3curl/openssl 旧curl -V检查
ALPN 协商 h2 但看不懂HTTP/2 二进制分帧用 Follow HTTP/2 Stream

十四、安全加固建议(运维向)

□ ssl_protocols 至少 TLSv1.2 TLSv1.3,优先淘汰 1.2 □ 证书 ECDSA P-256 或 RSA 2048+,自动续期 □ 启用 OCSP Stapling □ 评估 0-RTT:对外 API 建议 off □ 配置 HSTS(见 HTTPS 篇) □ 定期 sslscan / testssl.sh 扫描弱套件

testssl.sh 快测:

gitclone https://github.com/drwetter/testssl.sh.git ./testssl.sh--protocols192.168.56.30:443

十五、与攻击链的关联

TLS 1.3 普及 → 纯「拿服务器 RSA 私钥解流量」失效 → MITM 更依赖「用户信任恶意 CA」或 SSL 剥离 → 0-RTT 重放成为新审计点 → 元数据(SNI、JA3)仍是监控入口

下一篇SSL 剥离 将解释:即使有 HTTPS,为何仍可能「翻车」。


十六、完整实验步骤(90 分钟)

□ 1. nginx 开启 TLS 1.3,openssl s_client 验证 □ 2. 配置 SSLKEYLOGFILE + Wireshark TLS 密钥路径 □ 3. 隐私窗口访问 https://192.168.56.30,保存 full.pcapng □ 4. 定位 ClientHello,截图 supported_versions + key_share □ 5. 定位 ServerHello,确认选中 TLS 1.3 与套件 □ 6. 解密后展开 Certificate、ALPN □ 7. Follow HTTP/2 或 HTTP,确认应用层 □ 8. 再抓一包 curl --tlsv1.2,对比 Certificate 是否早期明文 □ 9. (可选)抓 0-RTT:同站第二次访问,查 early_data 扩展 □ 10. 填写「对照实验记录表」,写 200 字握手总结

十七、本篇小结

┌─────────────────────────────────────────────────────────────┐ │ TLS 1.3 核心记忆 │ ├─────────────────────────────────────────────────────────────┤ │ 1-RTT:ClientHello → ServerHello + 加密块 → Client Finished │ │ 版本在 supported_versions;key_share 完成 ECDHE │ │ Certificate 在握手加密段内,无密钥则 Wireshark「断层」 │ │ SSLKEYLOGFILE 是本地学习解密的最佳合法手段 │ │ 0-RTT 快但有重放风险;PFS 使历史密文难用长期私钥破解 │ └─────────────────────────────────────────────────────────────┘

下一篇预告:《一次真实的 SSL 剥离攻击:为什么 HTTPS 也会翻车》——HSTS、sslstrip、透明代理的组合拳。


附录 A:Wireshark 过滤器速查

tls tls.handshake.type == 1 tls.handshake.type == 2 tls.handshake.extensions_server_name tls.handshake.extensions.supported_versions tls.handshake.extensions_key_share tls.handshake.type == 8 ssl.handshake.type == 11 http2

附录 B:openssl 调试命令

# TLS 1.3 握手详情openssl s_client-connect192.168.56.30:443-tls1_3-msg# 查看套件openssl ciphers-v|grepTLS_AES# 会话复用测试openssl s_client-connect192.168.56.30:443-tls1_3-reconnect

附录 C:握手消息类型编号

Type名称TLS 1.3 常见
1ClientHello
2ServerHello
8EncryptedExtensions
11Certificate
15CertificateVerify
20Finished

附录 D:与专栏前篇关联

前篇关联
HTTP/HTTPS解密 Application Data 的前提
Wireshark显示过滤器 + TLS 密钥配置
ARP MITM握手可见,内容仍加密;剥离攻击在应用层