一、什么是网络流量指纹
网络流量指纹(Network Traffic Fingerprinting)是从网络通信的协议字段、报文顺序、连接行为、时间和大小等特征中提取相对稳定的模式,用来推测客户端软件、服务端技术栈、操作系统、协议、设备类型或异常行为的方法。
关键认识:指纹不是身份证。 多个程序可能共享同一个 TLS 库和指纹;同一程序也可能因为版本、配置、代理或随机化而产生不同指纹。指纹识别通常是概率性归类,而非绝对归因。
1.1 主要分类
| 类别 | 特征来源 | 典型技术 | 识别目标 |
|---|---|---|---|
| TCP/IP 指纹 | TTL、窗口大小、MSS、TCP 选项顺序 | p0f、Nmap OS Detection、JA4T | 操作系统或 TCP 实现 |
| TLS 客户端指纹 | ClientHello 中的套件、扩展、支持组 | JA3、JA4 | 客户端 TLS 栈或应用族 |
| TLS 服务端指纹 | ServerHello、探测响应 | JA3S、JA4S、JARM | 服务端 TLS 配置 |
| HTTP 指纹 | 方法、头字段、顺序、协议行为 | JA4H、HTTP/2 SETTINGS 指纹 | HTTP 客户端实现 |
| SSH 指纹 | 算法协商列表、握手特征 | HASSH、HASSHServer、JA4SSH | SSH 客户端或服务端 |
| DNS 指纹 | 查询名称、类型、间隔、响应模式 | DNS 行为画像 | 应用和异常通信 |
| 加密流量统计指纹 | 包长、方向、突发、时序 | 流统计、机器学习 | 流量类别或应用族 |
1.2 与其他指纹的区别
- Web 技术指纹:识别网站使用的 CMS、框架、服务器软件,如 WordPress、Nginx。
- 设备指纹:综合硬件、浏览器环境或网络特征识别设备。
- 网络流量指纹:重点观察网络上真实交换的数据包与协议协商行为。
二、指纹工作的底层原理
不同软件使用不同协议库、默认配置和实现策略。例如,TLS 客户端可以选择不同的密码套件、扩展、支持组以及扩展排列方式。观察这些差异,就能形成可比较的特征向量。
2.1 一个典型 HTTPS 连接
客户端 服务端
| -------- TCP SYN -------------------> |
| <------- TCP SYN/ACK ---------------- |
| -------- TCP ACK -------------------> |
| -------- TLS ClientHello -----------> | ← JA3 / JA4 的主要观察点
| <------- TLS ServerHello ----------- | ← JA3S / JA4S 的主要观察点
| <------- 后续 TLS 握手消息 ---------- | ← TLS 1.3 中多数后续握手内容加密
| <====== 加密应用数据 ==============> |
注意:TLS 1.3 的 ClientHello 和 ServerHello 通常可见,但后续握手消息多被加密。启用 ECH 后,真实的内部 ClientHello 中部分信息也可能不可见。QUIC 运行在 UDP 上,不经过 TCP 三次握手,其 Initial 数据包中的 TLS ClientHello 在没有 ECH 等保护时通常可以由被动分析器解码。
2.2 从报文到指纹的流水线
流量采集(PCAP / 镜像口 / TAP)
↓
会话关联(五元组、方向、连接状态)
↓
协议识别与解析(TCP / TLS / HTTP / SSH / QUIC)
↓
提取特征(字段值、列表、顺序、统计量)
↓
规范化(排除 GREASE、统一字段表示)
↓
生成指纹(结构化字符串 / 哈希 / 特征向量)
↓
指纹库匹配 + 行为上下文分析
↓
输出分类、置信度与调查线索
2.3 指纹为何能相对稳定
同一应用版本和 TLS 库往往重复使用相近的握手模板;但浏览器升级、A/B 实验、代理终止 TLS、负载均衡、系统库差异和协议随机化都可能改变结果。
2.4 GREASE 是什么
GREASE(Generate Random Extensions And Sustain Extensibility)在协议协商中插入保留值,避免网络生态错误依赖固定字段集合。JA3 会忽略 GREASE 值;JA4 也采用规范化设计来减轻列表顺序随机化等问题。忽略 GREASE 不代表可以忽略所有随机化。
三、指纹识别的完整过程
第一步:明确识别目标
例如判断“这批 HTTPS 连接是否来自同一类客户端”,与“这个服务器是否使用相似 TLS 配置”是两种不同任务。前者适合 JA3/JA4,后者适合 JA4S/JARM。
第二步:采集网络流量
在授权的测试主机上:
sudo tcpdump -i eth0 -s 0 -w tls-lab.pcap 'tcp port 443 or udp port 443'
-s 0 保留完整捕获长度;接口名根据实际环境调整。抓包前需考虑个人数据、合法授权及保存周期。
第三步:识别会话和握手
Wireshark 常用显示过滤器:
tls.handshake.type == 1 # TLS ClientHello
tls.handshake.type == 2 # TLS ServerHello
tcp.flags.syn == 1 # TCP SYN
quic # QUIC 数据包
http2 # HTTP/2 数据包
过滤字段依赖 Wireshark 版本、协议解码是否成功及抓包完整性。仅捕获中途流量可能看不到握手。
第四步:提取和规范化特征
以 TLS 为例,解析 ClientHello 的 legacy_version、cipher_suites、extensions、supported_groups、ec_point_formats。对 JA3,按规范过滤 GREASE 并保留相关列表顺序。对 JA4,使用对应版本的规范化规则;不能简单地把 JA3 字符串排序后称作 JA4。
第五步:生成指纹
可以生成原始可读字符串,再使用哈希便于存储和比较。哈希不是加密通信内容,也不具备唯一身份认证能力。
第六步:关联和验证
综合 SNI(如果可见)、DNS、目的 IP、证书元数据(如果可见)、HTTP 信息(如果可见)、时间分布、资产台账、进程日志和已知软件版本。优先在自己的实验环境建立“已知应用 → 指纹”基线。
第七步:输出结果
推荐记录:时间、源/目的、协议、指纹类型、指纹值、解析器版本、匹配依据、置信度、误报可能、建议的验证动作。
四、常用指纹技术详解
4.1 JA3:被动 TLS 客户端指纹
JA3 于 2017 年由 Salesforce 团队提出。它提取 ClientHello 的五组字段,按以下顺序构造字符串:
SSLVersion,Cipher,SSLExtension,EllipticCurve,EllipticCurvePointFormat
示例(官方示例):
769,47-53-5-10-49161-49162-49171-49172-50-56-19-4,0-10-11,23-24-25,0
对 UTF-8 字符串计算 MD5,得到 32 位十六进制 JA3 值。JA3 中的 SSLVersion 是特定握手字段,不应直接解释为最终协商的 TLS 版本,尤其是在 TLS 1.3 中。
优点:容易实现、容易共享、已有大量检测系统支持。缺点:对字段顺序敏感,可能因版本变化产生漂移;多个客户端可能共享指纹;MD5 不是身份保证。
4.2 JA3S:被动 TLS 服务端响应指纹
从 ServerHello 提取:
SSLVersion,Cipher,SSLExtension
经 MD5 得到 JA3S。它描述的是服务端对特定客户端握手的响应,同一服务器面对不同 ClientHello 可能产生不同 JA3S。实践中可以联合分析 JA3 + JA3S + 目的资产 + 时间。
4.3 JA4:改进的 TLS 客户端指纹
JA4 属于 FoxIO JA4+ 家族。与 JA3 相比,JA4 使用更易读的分段结构,并对相关字段做规范化处理,以改善某些随机化带来的指纹不稳定问题。它可以描述基于 TCP 的 TLS 和基于 QUIC 的 TLS 握手。
典型形式:
<协议标识与版本等摘要>_<密码套件摘要哈希>_<扩展摘要哈希>
其第一段通常包含传输协议标识、TLS 版本、SNI 状态、密码套件数量、扩展数量及 ALPN 信息;后两段根据规范化字段形成截断哈希。准确编码细节应以具体 JA4 实现版本的官方规范为准,不应自行拼接近似值并标注为标准 JA4。
JA4 的优势是便于分段检索和分析;局限是仍会有指纹共享、漂移、伪装以及可见性限制。
4.4 JA4S:TLS 服务端响应 / 会话指纹
JA4S 观察 ServerHello 等服务端响应特征,适合对 TLS 服务器及其与客户端的协商行为进行分组。它不是 JARM:JA4S 通常来自已发生的通信,而 JARM 主动发送探针。
4.5 JA4H:HTTP 客户端指纹
JA4H 侧重 HTTP 请求方法、协议、头字段及其他规范化特征。明文 HTTP 或在有合法解密/终止 TLS 的位置可以提取更多信息;在仅能被动看到加密 TLS 应用数据时,通常不能直接提取内部 HTTP 头。
4.6 JARM:主动 TLS 服务端指纹
JARM 是 Salesforce 提出的主动扫描技术,向目标 TLS 服务端发送 10 组特制 ClientHello 探测,记录服务器响应,再形成一个 62 字符的指纹。其前 30 字符编码各次探测的密码套件与 TLS 版本选择,后 32 字符来自响应扩展的摘要。
用途:资产配置一致性核验、服务器分组、调查可疑基础设施。它需要主动连接目标,可能产生访问日志,应仅扫描授权资产。不同服务器可以有相同 JARM,且同一服务器配置变更后也可能改变。
4.7 HASSH / HASSHServer:SSH 指纹
HASSH 依据 SSH 算法协商消息中的算法列表生成客户端指纹,HASSHServer 对应服务端。常用于识别 SSH 客户端族、自动化脚本或非典型实现。SSH 指纹反映的是协议栈特征,不代表用户身份。
4.8 p0f 与 Nmap OS Detection
- p0f:被动分析 TCP/IP 特征,推测操作系统、连接类型等,不必向目标主动发送专门探测包。
- Nmap OS Detection:通过主动发送多种 TCP/IP 探针并观察响应,推测操作系统;属于主动 OS 指纹识别,不等同于 JA3。
4.9 JA4+ 其他家族
| 名称 | 主要对象 |
|---|---|
| JA4L / JA4LS | 客户端/服务端方向的延迟测量特征 |
| JA4X | X.509 证书特征 |
| JA4SSH | SSH 流量特征 |
| JA4T / JA4TS | TCP 客户端/服务端特征 |
| JA4TScan | 主动 TCP 指纹探测 |
| JA4D / JA4D6 | DHCP / DHCPv6 特征 |
| JA4N | NTP 特征 |
| JA4Scan-TLS / JA4Scan-QUIC | 主动 TLS / QUIC 服务端探测 |
不同 JA4+ 项目的开源范围、许可和工具支持情况可能不同,使用前应核对官方仓库。
五、指纹技术横向对比
| 技术 | 主动/被动 | 观察位置 | 主要优点 | 主要局限 |
|---|---|---|---|---|
| JA3 | 被动 | TLS ClientHello | 简单、生态成熟 | 对顺序和实现变化敏感 |
| JA3S | 被动 | TLS ServerHello | 补充服务端视角 | 依赖客户端输入 |
| JA4 | 被动 | TLS / QUIC 客户端握手 | 结构可读、部分特征更稳定 | 仍可能共享或漂移 |
| JA4S | 被动 | TLS 服务端响应 | 适合会话关联 | 与客户端协商相关 |
| JA4H | 被动/解密点 | HTTP 请求 | HTTP 层信息丰富 | 加密 HTTP 需要可见性 |
| JARM | 主动 | TLS 服务端 | 无需现成客户端流量 | 会产生探测流量 |
| HASSH | 被动 | SSH 握手 | SSH 生态识别 | 共享实现造成重合 |
| p0f | 被动 | TCP/IP | 低干扰 OS 画像 | NAT/代理及网络设备干扰 |
| Nmap OS | 主动 | TCP/IP 响应 | 可获得更多探针特征 | 需授权、受防火墙影响 |
六、TLS 1.3、QUIC、ECH 与代理的影响
- TLS 1.3:ClientHello 和 ServerHello 的部分明文字段仍可用于指纹;握手后续内容大多加密。仅靠传统
legacy_version不能正确判定实际协商版本。 - QUIC / HTTP/3:使用 UDP 承载 TLS 1.3 握手,分析器必须理解 QUIC Initial 和相关握手编码;不能用“只抓 TCP 443”的方式完整覆盖。
- ECH:加密内部 ClientHello,减少真实 SNI 等敏感握手信息暴露。外层 ClientHello 仍可能提供有限特征,但可见性与归因能力下降。
- CDN / 反向代理:观察点可能只看到客户端到 CDN 的 TLS,无法直接推断源站 TLS 栈。
- VPN / 隧道:外部观察者通常看到的是隧道协议和外层连接,而不是隧道内每条应用连接的 TLS 指纹。
- TLS 中间人代理:如果代理终止并重建 TLS,两段连接会表现出不同的 TLS 客户端/服务端指纹。
- 指纹伪装:客户端可以调整 TLS 实现或握手字段,故单一指纹命中不能证明恶意行为。
七、授权实验:从抓包到指纹
实验 A:观察自己的 HTTPS 握手
准备 Wireshark / tshark、curl、tcpdump。先抓包,再访问自己控制的 HTTPS 测试服务。
sudo tcpdump -i eth0 -s 0 -w demo.pcap 'tcp port 443 or udp port 443'
curl -I https://your-authorized-test-host.example
在 Wireshark 中用 tls.handshake.type == 1 定位 ClientHello,展开 Cipher Suites、Extensions、Supported Groups 等字段,比较不同客户端或软件版本的差异。
实验 B:从已知 JA3 原始字符串计算 MD5
下面代码仅演示 JA3 的最后一步:字符串哈希;并未实现 TLS 解析、GREASE 过滤或完整 JA3 提取。
import hashlib
ja3_string = (
"769,47-53-5-10-49161-49162-49171-49172-50-56-19-4,"
"0-10-11,23-24-25,0"
)
fingerprint = hashlib.md5(ja3_string.encode("utf-8")).hexdigest()
print("JA3 raw:", ja3_string)
print("JA3 hash:", fingerprint)
预期哈希:ada70206e40642a3e4461f35503241d5。
实验 C:JARM 检查自有 TLS 服务器
使用官方仓库,在允许主动扫描的测试网络运行:
git clone https://github.com/salesforce/jarm.git
cd jarm
python3 jarm.py your-authorized-test-host.example
对比同一实验服务器在不同 TLS 配置下的结果,并记录软件版本、证书和配置。不要将相同 JARM 解释为同一服务器所有权。
实验 D:建立指纹基线
在同一台实验主机上分别使用浏览器、curl、Python requests 访问自有服务,记录 ClientHello 特征及 JA3/JA4(如果分析工具支持),然后升级其中一个客户端,观察指纹是否变化。
| 时间 | 客户端与版本 | TLS 指纹 | SNI/目的 | 备注 |
|---|---|---|---|---|
| 实验前 | curl(填写版本) | 实测填写 | 自有测试域名 | 基线 |
| 实验前 | 浏览器(填写版本) | 实测填写 | 自有测试域名 | 基线 |
| 升级后 | curl(新版本) | 实测填写 | 自有测试域名 | 比较漂移 |
八、在安全运营中的识别策略
不要把“匹配某个恶意样本曾用过的 JA3”直接等同于“检测到恶意软件”。 推荐分层判断:
- 指纹是否在本单位正常资产基线中出现?
- 该连接是否具有异常 DNS、异常目标地址或不寻常的时间模式?
- 是否存在周期性回连、极低数据量但长时间持续的行为?
- 主机 EDR、进程树、代理日志是否能验证发起进程?
- 同一指纹是否广泛存在于正常软件中?
- 能否通过隔离实验复现,排除 CDN、代理和共享 TLS 库造成的误判?
8.1 置信度分级建议
- 低:仅有单个指纹命中。
- 中:指纹命中 + 异常目的地或时间行为。
- 高:指纹、网络行为、主机进程证据与已验证威胁情报相互印证。
以上是教学性分级示例,实际检测系统应基于真实环境评估误报率、漏报率和基线覆盖率。
8.2 常见误判来源
- 浏览器与恶意程序使用同一 TLS 库;
- 客户端版本升级导致指纹变化;
- 代理、WAF、CDN 重建连接;
- 数据包丢失、TCP 分片或抓包起点太晚;
- GREASE、扩展顺序随机化;
- QUIC/ECH 导致字段不可见或解析不完整;
- 不同指纹工具实现版本、规范和解析策略不一致。
九、学习路线与知识检查
阶段 1(1—3 天):复习 TCP/IP、三次握手、TLS 1.2/1.3、HTTP/2、QUIC,熟悉 Wireshark 的握手解析。
阶段 2(4—6 天):手工理解 JA3 原始字段和 MD5,比较 JA3、JA3S、JA4、JA4S 的目标和差异。
阶段 3(7—9 天):在自有服务器运行 JARM;用 p0f/Nmap 对照理解被动与主动探测。
阶段 4(10—12 天):采集多种客户端的 PCAP,建立基线,记录软件升级、代理切换和 QUIC 开关造成的变化。
阶段 5(13—14 天):建立简单的关联分析表,评价误报与漏报,形成检测报告。
自测问题:
- 为什么 JA3 不等于设备唯一 ID?
- 为什么 JA3S 可能随 ClientHello 变化?
- JARM 与 JA4S 的主动/被动差别是什么?
- 为什么仅有加密 TLS 流量时无法直接得到完整 JA4H?
- QUIC 为什么不能只依赖 TCP 443 抓包?
- ECH 为什么会降低被动识别的可见性?
十、术语速查
- ClientHello:客户端发起 TLS 协商的握手消息。
- ServerHello:服务端对协商参数的选择响应。
- Cipher Suite:密码套件标识;TLS 1.3 与早期版本的语义不同。
- TLS Extension:TLS 扩展字段,承载支持版本、ALPN、SNI 等信息。
- SNI:Server Name Indication,通常表示期望访问的主机名;ECH 可隐藏真实内层名称。
- ALPN:应用层协议协商,如 h2、http/1.1。
- GREASE:为防止协议生态僵化而插入的保留协商值。
- 五元组:源 IP、源端口、目的 IP、目的端口、传输层协议。
- 被动指纹:分析已有通信,不额外主动发探测。
- 主动指纹:向目标发送专门探针,观察响应差异。
- 指纹漂移:同一应用/资产随版本或配置变化而产生不同指纹。
十一、参考资料与官方项目
- Salesforce JA3 / JA3S:https://github.com/salesforce/ja3 (原仓库已归档)
- FoxIO JA4+ 项目:https://github.com/FoxIO-LLC/ja4
- FoxIO JA4+ 技术介绍:https://blog.foxio.io/ja4%2B-network-fingerprinting
- Salesforce JARM:https://github.com/salesforce/jarm
- Wireshark 官方文档:https://www.wireshark.org/docs/
- Zeek 官方文档:https://docs.zeek.org/
- Suricata 官方文档:https://docs.suricata.io/
- Nmap OS Detection:https://nmap.org/book/osdetect.html
- RFC 8446(TLS 1.3):https://www.rfc-editor.org/rfc/rfc8446
- RFC 9000(QUIC):https://www.rfc-editor.org/rfc/rfc9000
- RFC 9001(QUIC TLS):https://www.rfc-editor.org/rfc/rfc9001
总结: 网络流量指纹的本质是“从协议实现差异和通信行为中提取可重复比较的特征”。JA3/JA4 侧重 TLS 客户端,JA3S/JA4S 侧重服务端响应,JARM 主动探测服务端,HASSH 观察 SSH,TCP/IP 指纹补充操作系统视角。最可靠的检测方式是将指纹与网络行为、资产信息及主机证据联合使用。
浙公网安备 33010602011771号