SSL证书握手是建立 HTTPS 连接的核心环节。用 Wireshark 抓包分析时,核心难点在于如何解密流量,因为握手过程中的密钥交换部分通常是加密的。下面是一套从环境准备到逐步分析的实战流程。
第一步:环境准备(解密的关键)
默认情况下,Wireshark 看到的是加密的“Application Data”。要分析明文握手包,必须让 Wireshark 能够解密。
方法:导出浏览器会话密钥(最常用)
1. 设置环境变量:
在 Windows 或 Linux 中设置变量,让浏览器(Chrome/Firefox)将密钥写入文件。
bash
# Windows (CMD)
set SSLKEYLOGFILE=C:\Users\你的用户名\Desktop\sslkeys.txt
# Linux/Mac (终端启动浏览器)
export SSLKEYLOGFILE=/Users/你的用户名/Desktop/sslkeys.txt
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome
2. 配置 Wireshark:
编辑 -> 首选项 -> Protocols -> TLS(或 SSL)-> 在“(Pre)-Master-Secret log filename”中填入上述文件路径。
验证:抓包后,如果看到 “Decrypted SSL data” 或绿色高亮的包,说明解密成功。
第二步:开始抓包
1. 打开 Wireshark,选择网卡(通常是有流量的那个)。
2. 过滤:在过滤栏输入 `tls` 或 `ssl`(旧版本)。如果是访问特定网站,建议输入 `ip.addr == 目标IP and tls`。
3. 触发握手:在浏览器访问 `https://www.example.com`。
第三步:逐包分析握手过程
SSL/TLS 1.2 和 1.3 略有不同。以经典的 TLS 1.2 为例,通常看到以下 5-6 个核心包:
包 1:Client Hello
目的 :客户端告诉服务器“我想建立安全连接”。
关键字段:
Random:客户端生成的 32 字节随机数。
Cipher Suites:客户端支持的加密套件列表(如 `TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384`)。这里能看到是否支持前向加密。
Extension: Server Name Indication (SNI):非常重要。这里会明文显示你要访问的域名(如 `www.example.com`)。如果这里没有域名或域名错误,可能导致证书报错。
包 2:Server Hello
目的:服务器选择加密参数。
关键字段:
Random:服务器生成的 32 字节随机数。
Cipher Suite:服务器选定的加密套件。
Compression Methods:通常为 null。
包 3:Certificate, Server Key Exchange, Server Hello Done
Certificate:服务器发送数字证书。
展开查看:`Certificate` -> `SignedCertificate` -> `Certificate` -> `tbdsCertificate` -> `subject`(域名)和 `issuer`(颁发者)。
可以检查证书链是否完整,是否包含了中间证书。
Server Key Exchange:发送密钥交换参数。
如果是 ECDHE 算法,这里会包含 `Server Params`(椭圆曲线参数和公钥)。
Server Hello Done:表示服务器消息结束。
包 4:Client Key Exchange, Change Cipher Spec, Encrypted Handshake Message
Client Key Exchange:
如果是 RSA 密钥交换,这里是加密后的 Pre-Master Secret。
如果是 ECDHE(现代多数情况),这里是客户端的椭圆曲线公钥。
Change Cipher Spec:这是一个独立的协议。它告诉对方:“我算好了密钥,接下来的数据我将用协商好的密钥加密。”
Encrypted Handshake Message (Finished):这是第一个被加密的包。内容是对之前所有握手数据的摘要校验。
包 5:New Session Ticket, Change Cipher Spec, Encrypted Handshake Message
New Session Ticket:服务器发来的 Session Ticket,用于下次连接时做会话复用(Session Resumption),避免再次进行完整握手。
Change Cipher Spec:服务器通知客户端,它也要切换加密模式了。
Encrypted Handshake Message (Finished):服务器确认握手完成。
第四步:高阶排查点(实战常见问题)
1. 找不到 Server Hello?(Server 端没有响应)
在过滤栏输入 `tcp.flags.reset == 1`。
如果看到 RST 包,通常是服务器直接拒绝连接。
如果看到 TCP Retransmission,可能是防火墙拦截了 TLS 流量,或服务器端口(443)不通。
2. 证书配置错误
查看 Certificate 包下面的 `Alert` 包(通常 Level: Fatal)。
Alert (Level: Fatal, Description: Unknown CA):客户端不信任该证书(缺少根证书)。
Alert (Description: Certificate Expired):证书过期。
Alert (Description: Hostname Mismatch):证书域名与 SNI 不匹配。
3. TLS 版本不匹配
在 Client Hello 中查看 Supported Versions。
如果服务器响应一个 Alert (Protocol Version),说明服务器不支持客户端请求的最高 TLS 版本。
"案例":老旧服务器只支持 TLS 1.0,而现代浏览器默认请求 TLS 1.2/1.3,连接失败。
4. 性能瓶颈分析(握手耗时)
利用 Wireshark 的 Statistics -> Flow Graph。
重点看 Client Hello 到 Server Hello 的时间:衡量服务器响应速度及网络 RTT。
重点看 Client Key Exchange 到 Finished 的时间:衡量客户端计算密钥及服务器验证的时间。
第五步:TLS 1.3 的差异
TLS 1.3 简化了握手过程(1-RTT 甚至 0-RTT)。
1. 包更少:`Server Hello` 之后直接包含 `Change Cipher Spec`(为了兼容中间设备)和 `Encrypted Extensions`。
2. 加密更早:在 TLS 1.3 中,Certificate 包在 `Server Hello` 之后也是加密的。
如果你没有配置 Wireshark 的密钥文件,在 TLS 1.3 中你将看不到证书的明文域名。只有配置了 `SSLKEYLOGFILE`,证书才会显示为绿色解密状态。
总结实战命令(Wireshark 显示过滤器)
`tls.handshake.type == 1`:只看 Client Hello
`tls.handshake.type == 11`:只看 Certificate(证书包)
`tls.alert_message.level == 2`:只看致命警报(错误)
`tls.handshake.extensions_server_name`:快速筛选出包含 SNI 域名的包
用户通过以上步骤,你不仅能看清握手全貌,还能精准定位SSL证书过期、协议不兼容、防火墙拦截等常见生产环境问题。