SSL/TLS 加密流量分析
加密流量分析,说白了就是要在不破解加密内容的前提下,把网络里的 TLS 流量看个大概。嗯,这活儿挺考验耐心。
我个人习惯把 TLS 分析分成四步:握手过程、证书链验证、SNI 字段提取、加密流分类。每一步都有坑,我一个个讲。
TLS 握手过程——不仅仅是“你好我好”
TLS 握手,本质上是在建立加密隧道之前,双方先互相打个照面,确认身份、商定密钥。我用 Wireshark 抓过上千个握手包,总结下来核心就这五步:
- Client Hello:客户端打招呼,告诉服务器它支持哪些 TLS 版本、密码套件,还带一个随机数。
- Server Hello:服务器从客户端列表里挑一个,选好版本和密码套件,也发个随机数。同时把自己的证书丢过来。
- 证书链与 Server Hello Done:服务器发完证书就说“我说完了”。
- 客户端密钥交换 + Change Cipher Spec:客户端生成随机数,用服务器公钥加密发过去。然后双方各自算出对称密钥。
- Handshake Finished:两边互相确认,握手结束。
你想想看,这里面最容易出问题的就是第三步。证书链如果断了一环,客户端就会报警。
证书链验证——信任的链条不能断
服务器发的证书不是孤立的。它是一串链:服务器证书 → 中间 CA 证书 → 根证书。浏览器或 DLP 设备收到后,会从根开始逐级验证签名。
我曾在项目里遇到过一件事:某网银系统的中间 CA 证书在本地信任库里缺失了,结果所有 TLS 流量都被判定为“证书无效”。当时排查了整整一下午,最后发现是运维没上传完整证书链。真是坑。
| 证书层级 | 作用 | 常见问题 |
|---|---|---|
| 根证书 | 信任锚点,预置在操作系统或浏览器中 | 过期、撤销(CRL/OCSP) |
| 中间CA证书 | 由根签发,负责签署服务器证书 | 链不完整、未上传 |
| 服务器证书 | 最终用于加密通信 | 域名不匹配、有效期短 |
做 DLP 扫描时,建议把证书链验证结果作为一个特征维度。比如“链长度”、“根证书是否在可信列表”。这些都能帮你区分合法流量和恶意流量。
SNI 字段提取——加密流量的“门牌号”
TLS 加密后,你没法直接看到 HTTP Host 头。但 Client Hello 里有个明文字段叫 SNI(Server Name Indication)。它告诉服务器你要访问哪个域名。这个字段是明文,没加密。
我记得第一次写 SNI 提取脚本时,踩了个坑:有些客户端(比如旧版 IE)不支持 SNI,Client Hello 里就没这个字段。另外,如果流量走的是代理隧道,SNI 可能会被覆盖。所以提取时一定要做空值判断。
# 用 scapy 提取 SNI 的简单示例(Python)
from scapy.all import *
def extract_sni(packet):
if packet.haslayer(TLS):
tls_layer = packet[TLS]
for msg in tls_layer.msg:
if msg.content_type == 22: # Handshake
handshake = msg
for ext in handshake.extensions:
if ext.type == 0: # server_name
sni = ext.server_name
return sni.decode('utf-8', errors='ignore')
return None
加密流分类——给流量打标签
有了握手信息和 SNI,就能对 TLS 流进行分类了。我一般从三个维度下手:
- 基于 SNI 域名:白名单/黑名单匹配。比如 *.bank.com 归为金融类。
- 基于 JA3 指纹:Client Hello 中的密码套件、扩展、椭圆曲线等组合成一个哈希值。不同客户端/工具的特征不同。例如,curl 和 Chrome 的 JA3 不一样。
- 基于证书特征:颁发者、有效期、公钥长度等。
举个实际例子。我在某个项目里,靠 JA3 识别出了内网一台机器在用 Python requests 库大量访问外部 API。运维原以为是正常的浏览器流量,一查 JA3 指纹才发现是自动化脚本。
| 分类维度 | 提取方式 | 优势 | 不足 |
|---|---|---|---|
| SNI | Client Hello 明文 | 直接、低开销 | 依赖客户端支持,可能缺失 |
| JA3 | 握手参数哈希 | 识别工具/客户端版本 | 需要维护 JA3 特征库 |
| 证书 | 服务器证书解析 | 判断可信度、到期时间 | 解析开销稍大 |
老实说,这套流程看似简单,但实际部署时麻烦不少。比如在高并发场景下,JA3 计算会消耗 CPU;或者 SNI 字段可能被恶意篡改(虽然少见)。
我曾经遇过一个案例:某台被控的服务器用自定义 TLS 客户端,它的 JA3 指纹根本不在公开库里。后来我抓了它的证书特征——自签名、有效期 10 年、公钥是 512 位——立刻判定为可疑流量。最终确认是挖矿木马。