tls
明白!你想要一份完整、结构清晰、逻辑严密的 TLS(单向和双向)建立流程文档,重点聚焦:
-
自签证书环境下的抓包判断
-
详尽补充所有重要 Alert 的含义、成因与排查
-
结合 Wireshark 过滤表达式,帮助定位具体失败原因
-
文档条理清晰、不混淆,适合实战使用
下面我为你整理出一份极完整的 TLS 建立过程抓包分析文档(单向 & 双向,含自签证书环境重点),并详细补充 Alert 报文的含义及定位方案。结构分明,内容详实,方便实战查错和学习。
完整文档:TLS 建立过程抓包详解(含单向、双向及自签证书异常排查)
1. 前言
本指南详尽介绍 TLS 握手的各个阶段报文及其含义,重点拆分:
-
单向 TLS(仅服务器证书验证)
-
双向 TLS(服务器和客户端均需证书)
同时特别针对 自签证书环境,说明如何利用 Wireshark 抓包判断:
-
客户端是否携带证书访问
-
常见证书链和认证失败的 Alert 报文含义与排查方向
2. 单向 TLS 完整流程及抓包分析
| 步骤 | Wireshark 过滤表达式 | 报文类型 / 含义 | 自签环境注意点 |
|---|---|---|---|
| 1 | tcp.flags.syn == 1 |
TCP 三次握手建立连接 | 网络层连通,确保后续 TLS 建立条件 |
| 2 | tls.handshake.type == 1 |
ClientHello | 客户端发起握手,列出支持的版本和加密套件 |
| 3 | tls.handshake.type == 2 |
ServerHello | 服务端确认版本和加密套件 |
| 4 | tls.handshake.type == 11 && ip.src == <server_ip> |
服务器发送证书链(自签时通常为根证书) | 客户端需信任自签证书,否则后续握手失败 |
| 5 | tls.handshake.type == 14 |
ServerHelloDone | 服务器完成握手消息发送 |
| 6 | tls.handshake.type == 16 |
ClientKeyExchange | 客户端发送密钥交换信息 |
| 7 | tls.record.content_type == 20 |
ChangeCipherSpec | 客户端通知开始加密通信 |
| 8 | tls.handshake.type == 20 |
Finished | 客户端完成握手,发送 Finished 消息 |
| 9 | tls.record.content_type == 20 |
ChangeCipherSpec | 服务器通知开始加密通信 |
| 10 | tls.handshake.type == 20 |
Finished | 服务器完成握手,发送 Finished 消息 |
| 11 | tls.record.content_type == 23 |
Application Data | 双方开始加密数据传输 |
单向 TLS 常见失败及排查点
| 失败类型 | Wireshark 报文或 Alert | 排查方向(自签环境) |
|---|---|---|
| 证书链不受信任 | tls.alert_message.description == unknown_ca 或 bad_certificate |
客户端未导入/信任自签根证书 |
| TLS 版本不兼容 | tls.alert_message.description == protocol_version |
客户端与服务端 TLS 版本配置不匹配 |
| 加密套件不匹配 | tls.alert_message.description == handshake_failure |
加密套件不兼容或缺失 |
| Finished 校验失败 | tls.alert_message.description == decrypt_error 或 bad_record_mac |
密钥协商失败,密钥计算不一致 |
3. 双向 TLS 完整流程及抓包分析
| 步骤 | Wireshark 过滤表达式 | 报文类型 / 含义 | 自签环境重点 |
|---|---|---|---|
| 1 | tcp.flags.syn == 1 |
TCP 三次握手建立连接 | 网络层连通 |
| 2 | tls.handshake.type == 1 |
ClientHello | 客户端发起握手 |
| 3 | tls.handshake.type == 2 |
ServerHello | 服务器确认版本和加密套件 |
| 4 | tls.handshake.type == 11 && ip.src == <server_ip> |
服务器证书 | 自签证书链 |
| 5 | tls.handshake.type == 13 |
CertificateRequest | 服务器请求客户端证书,双向认证开始 |
| 6 | tls.handshake.type == 14 |
ServerHelloDone | 服务器完成握手,等待客户端响应 |
| 7 | tls.handshake.type == 11 && ip.src == <client_ip> |
客户端证书 | 关键报文,判断客户端是否携带证书 |
| 8 | tls.handshake.type == 15 |
CertificateVerify | 客户端签名验证证书所有权 |
| 9 | tls.handshake.type == 16 |
ClientKeyExchange | 客户端密钥交换参数 |
| 10 | tls.record.content_type == 20 |
ChangeCipherSpec | 客户端通知开始加密通信 |
| 11 | tls.handshake.type == 20 |
Finished | 客户端完成握手 |
| 12 | tls.record.content_type == 20 |
ChangeCipherSpec | 服务器开始加密通信 |
| 13 | tls.handshake.type == 20 |
Finished | 服务器完成握手 |
| 14 | tls.record.content_type == 23 |
Application Data | 双方加密数据传输 |
判断客户端是否携带证书访问
| 判断点 | Wireshark 过滤表达式 | 说明 |
|---|---|---|
| 服务器是否发 CertificateRequest | tls.handshake.type == 13 |
服务器请求客户端证书,开启双向认证 |
| 客户端是否发 Client Certificate | tls.handshake.type == 11 && ip.src == <client_ip> |
若无此报文,客户端未携带证书,握手必失败 |
| 服务器返回证书相关 Alert | tls.alert_message.description == certificate_required 或 bad_certificate |
服务器拒绝无证书访问或证书无效 |
| 客户端发送 CertificateVerify | tls.handshake.type == 15 |
客户端签名验证,缺失或失败均导致握手失败 |
双向 TLS 典型异常及含义
| 异常情况 | Wireshark 报文或 Alert | 自签环境重点排查方向 |
|---|---|---|
| 客户端无证书 | 服务器发 CertificateRequest,客户端无 Certificate 报文 | 客户端未带证书或配置缺失证书 |
| 客户端证书格式或私钥错误 | Alert: bad_certificate 或握手失败 |
证书格式异常或私钥和证书不匹配 |
| 客户端证书不被服务端信任 | Alert: unknown_ca |
服务端未导入客户端证书的 CA(自签根证书) |
| 客户端证书签名校验失败 | CertificateVerify 报文异常或握手失败 | 签名验证失败,私钥不匹配或签名算法问题 |
| Finished 消息校验失败 | Alert: decrypt_error 或 bad_record_mac |
密钥协商失败,双方密钥不一致 |
4. 常见 TLS Alert 报文详解及排查方向
| Alert 名称 | 含义摘要 | Wireshark 过滤表达式 | 排查建议(自签场景重点) |
|---|---|---|---|
close_notify |
正常关闭通知 | tls.alert_message.description == close_notify |
正常关闭,非错误 |
unexpected_message |
收到意外消息 | tls.alert_message.description == unexpected_message |
协议流程异常,检查 TLS 版本和实现是否兼容 |
bad_record_mac |
消息认证码错误 | tls.alert_message.description == bad_record_mac |
密钥协商失败,密钥不一致或被篡改 |
decryption_failed_RESERVED |
解密失败(保留) | tls.alert_message.description == decryption_failed_RESERVED |
同上 |
record_overflow |
报文长度异常 | tls.alert_message.description == record_overflow |
报文格式异常,可能是网络或软件问题 |
handshake_failure |
握手失败 | tls.alert_message.description == handshake_failure |
协议或加密套件不兼容 |
bad_certificate |
证书无效 | tls.alert_message.description == bad_certificate |
证书格式错误或证书链不完整,自签时多为客户端证书问题 |
unsupported_certificate |
不支持的证书类型 | tls.alert_message.description == unsupported_certificate |
证书类型或算法不支持 |
certificate_revoked |
证书被吊销 | tls.alert_message.description == certificate_revoked |
CRL/OCSP 状态异常,自签证书关注吊销列表更新 |
certificate_expired |
证书过期 | tls.alert_message.description == certificate_expired |
证书超过有效期,自签证书需要定期更新 |
certificate_unknown |
证书未知 | tls.alert_message.description == certificate_unknown |
证书验证失败,根 CA 未导入或链不完整 |
illegal_parameter |
非法参数 | tls.alert_message.description == illegal_parameter |
参数错误,协议或实现缺陷 |
unknown_ca |
未知 CA | tls.alert_message.description == unknown_ca |
自签根 CA 未信任,客户端未导入根证书 |
access_denied |
访问被拒绝 | tls.alert_message.description == access_denied |
证书权限或策略限制 |
decode_error |
解码错误 | tls.alert_message.description == decode_error |
证书或消息格式错误 |
decrypt_error |
解密错误 | tls.alert_message.description == decrypt_error |
密钥协商失败,双方密钥不一致 |
protocol_version |
协议版本不匹配 | tls.alert_message.description == protocol_version |
TLS 版本配置不匹配 |
insufficient_security |
安全等级不足 | tls.alert_message.description == insufficient_security |
加密套件安全级别不足 |
internal_error |
内部错误 | tls.alert_message.description == internal_error |
软件实现错误 |
user_canceled |
用户取消 | tls.alert_message.description == user_canceled |
用户主动取消,非错误 |
no_renegotiation |
禁止重新协商 | tls.alert_message.description == no_renegotiation |
重新协商被禁用 |
5. Wireshark 常用过滤表达式总结
| 目的 | 过滤表达式 | 说明 |
|---|---|---|
| 抓取 ClientHello 报文 | tls.handshake.type == 1 |
握手起点 |
| 抓取 ServerHello 报文 | tls.handshake.type == 2 |
服务器确认 |
| 抓取服务端 Certificate 报文 | tls.handshake.type == 11 && ip.src == <server_ip> |
服务器证书 |
| 抓取 CertificateRequest 报文 | tls.handshake.type == 13 |
服务器请求客户端证书 |
| 抓取客户端 Certificate 报文 | tls.handshake.type == 11 && ip.src == <client_ip> |
客户端证书 |
| 抓取 CertificateVerify 报文 | tls.handshake.type == 15 |
客户端签名验证 |
| 抓取所有 Alert 报文 | tls.record.content_type == 21 |
包含所有警告和错误 |
| 抓取证书相关失败 Alert | `tls.record.content_type == 21 && (tls.alert_message.description == certificate_required | |
| 抓取握手失败 Alert | tls.record.content_type == 21 && tls.alert_message.description == handshake_failure |
协议或套件不兼容导致握手失败 |
6. 自签双向 TLS 抓包排查关键步骤(示例)
# 1. 确认 TCP 三次握手成功
tshark -r capture.pcap -Y "tcp.flags.syn==1"
# 2. 确认服务端发送自签证书
tshark -r capture.pcap -Y "tls.handshake.type==11 && ip.src==<server_ip>" -V | grep -A20 "Certificate"
# 3. 确认服务器请求客户端证书
tshark -r capture.pcap -Y "tls.handshake.type==13"
# 4. 判断客户端是否发送证书
tshark -r capture.pcap -Y "tls.handshake.type==11 && ip.src==<client_ip>"
# 5. 检查证书缺失或认证失败的 Alert
tshark -r capture.pcap -Y "tls.record.content_type==21 && (tls.alert_message.description==certificate_required || tls.alert_message.description==bad_certificate)"
# 6. 确认客户端证书签名验证报文
tshark -r capture.pcap -Y "tls.handshake.type==15"
# 7. 跟踪 Finished 消息是否正常
tshark -r capture.pcap -Y "tls.handshake.type==20"
7. 额外支持
如你需要,我可以:
-
帮你写一份 自动判定客户端证书缺失或验证失败的 tshark 命令脚本
-
结合你抓包文件帮你 具体定位 TLS 建立失败的根因
-
制作 清晰的 TLS 握手时序图,标注关键报文和异常位置
总结
-
本文档逻辑清晰,先分单向和双向流程,再详尽补充所有 Alert 的含义与过滤表达式
-
自签证书环境下,结合上述关键报文(
CertificateRequest、Client Certificate、CertificateVerify)和 Alert 判断客户端是否携带证书及验证状态 -
结合 Wireshark 过滤表达式和 tshark 命令,方便你快速精准排查 TLS 握手问题
如果你需要,我可立刻帮你基于此写具体排查脚本或示例抓包解析,你觉得如何?
浙公网安备 33010602011771号