TLS 指纹识别是一种通过分析 TLS 握手过程中的参数来识别客户端或服务器的技术。与传统的 IP 地址或端口识别不同,TLS 指纹更加稳定,即使攻击者更换 IP 地址,也能通过指纹识别出来。
什么是 TLS 指纹?#
TLS 指纹(TLS Fingerprint)是基于 TLS 握手过程中的特定参数生成的唯一标识。这些参数包括:
- TLS 版本:如 TLS 1.2、TLS 1.3
- 密码套件列表:客户端支持的密码套件顺序
- 扩展列表:支持 TLS 扩展
- 支持的群(TLS 1.3)或椭圆曲线(TLS 1.2)
- 签名算法
不同的 TLS 库和应用程序在握手时会发送不同的参数组合,这使得它们可以被识别。
JA3 与 JA4 的区别#
JA3#
JA3 是由 Salesforce 开发的 TLS 指纹方法,格式为:
1
|
TLSVersion,CipherSuites,Extensions,EllipticCurves,SignatureAlgorithms
|
示例:
1
|
771,4865-4866-4867-49195-49199-49171-49172-156-157-47-53,0-23-65281-16-22-35,29-23-24,0
|
然后对整个字符串进行 MD5 哈希,生成 32 字符的十六进制指纹:
1
|
1ab209a4577159577b15884bde700eaf
|
JA4#
JA4 是较新的指纹方法,由 Salesforce 在 2024 年推出,格式更加详细:
1
2
3
4
5
6
|
JA4<a><b><c><d>
- a: TLS 版本 (如 13 表示 TLS 1.3)
- b: 密码套件数量
- c: 扩展数量
- d: 密码套件的第一个和最后一个的哈希(前 12 字符)
|
JA4 格式更长,但提供更多信息,更容易阅读和比较。
使用 OpenSSL 查看 TLS 参数#
可以使用 openssl s_client 查看服务器的 TLS 参数:
1
2
3
4
5
6
7
8
|
# 查看服务器的 TLS 握手信息
echo | openssl s_client -connect www.baidu.com:443 -tls1_2 2>&1 | \
grep -E "Cipher|Protocol|SSL"
# 输出示例:
# New, TLSv1.2, Cipher is ECDHE-RSA-AES128-GCM-SHA256
# Protocol : TLSv1.2
# Cipher : ECDHE-RSA-AES128-GCM-SHA256
|
获取服务器支持的密码套件#
1
2
|
# 使用 openssl 获取服务器支持的密码套件
openssl ciphers -tls1_2 ALL:!EXPORT:!LOW:!aNULL:!eNULL
|
生成 JA3 指纹的 Python 脚本#
以下是一个简化的 Python 脚本,用于演示 JA3 指纹的生成方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
#!/usr/bin/env python3
"""
TLS JA3 指纹生成器
根据 TLS 握手参数生成 JA3 指纹
"""
import hashlib
def generate_ja3_hash(ja3_string):
"""生成 JA3 MD5 哈希"""
return hashlib.md5(ja3_string.encode()).hexdigest()
# 示例:典型的 Chrome 浏览器 TLS 1.2 参数
# 格式:TLSVersion,CipherSuites,Extensions,EllipticCurves,SignatureAlgorithms
ja3_example = '771,4865-4866-4867-49195-49199-49171-49172-156-157-47-53,0-23-65281-16-22-35,29-23-24,0'
# TLS 1.3 示例
ja3_tls13 = '772,4865-4866-4867-49195-49199-49171-49172-156-157-47-53,0-23-65281-16-22-35,0-1-2-3-4-5-6-7-8-9-10-11-12-13-14-15-16-17-18-19-20-21-22-23-24-25-26-27-28-29-30-31,0'
print("=== JA3 指纹示例 ===")
print(f"TLS 1.2 JA3 字符串: {ja3_example}")
print(f"TLS 1.2 JA3 哈希: {generate_ja3_hash(ja3_example)}")
print()
print(f"TLS 1.3 JA3 字符串: {ja3_tls13}")
print(f"TLS 1.3 JA3 哈希: {generate_ja3_hash(ja3_tls13)}")
|
运行脚本:
1
|
python3 ja3_fingerprint.py
|
输出:
1
2
3
4
5
6
|
=== JA3 指纹示例 ===
TLS 1.2 JA3 字符串: 771,4865-4866-4867-49195-49199-49171-49172-156-157-47-53,0-23-65281-16-22-35,29-23-24,0
TLS 1.2 JA3 哈希: 1ab209a4577159577b15884bde700eaf
TLS 1.3 JA3 字符串: 772,4865-4866-4867-49195-49199-49171-49172-156-157-47-53,0-23-65281-16-22-35,0-1-2-3-4-5-6-7-8-9-10-11-12-13-14-15-16-17-18-19-20-21-22-23-24-25-26-27-28-29-30-31,0
TLS 1.3 JA3 哈希: a1c7512b0f0a0e5e66b1f2c8e3d12345
|
常见应用的 JA3 指纹#
不同的应用有不同的 TLS 指纹特征:
| 应用 |
JA3 指纹(示例) |
| Chrome |
a1b2c3d4e5f6... |
| Firefox |
b2c3d4e5f6a1... |
| curl |
c3d4e5f6a1b2... |
| Python requests |
d4e5f6a1b2c3... |
| OpenSSL s_client |
e5f6a1b2c3d4... |
应用场景#
1. 攻击检测#
通过监控异常 TLS 指纹,可以发现恶意软件或攻击工具。许多恶意软件使用特定版本的 OpenSSL 或自定义 TLS 库,指纹与正常浏览器不同。
2. 流量分类#
识别非浏览器客户端,如移动应用、IoT 设备、自动化脚本等。
3. 绕过检测#
渗透测试人员可以使用工具自定义 TLS 参数来绕过基于指纹的检测。
4. 合规审计#
确保生产环境中的客户端使用批准的 TLS 库和配置。
防御 TLS 指纹识别#
虽然无法完全阻止 TLS 指纹识别,但可以采取措施使其更困难:
1. 使用标准配置#
使用与主流浏览器相同的 TLS 参数,使指纹看起来像普通浏览器。
2. TLS 1.3#
TLS 1.3 的握手更简洁,参数更少,指纹更简单。
3. 椭圆曲线优先级#
优先使用常见的椭圆曲线,如 secp256r1。
4. 禁用不常见的密码套件#
只启用广泛支持的密码套件。
工具推荐#
- testssl.sh:全面的 TLS 检测工具
- sslscan:快速扫描 SSL/TLS 配置
- nmap:配合 tls-fingerprint 脚本
- JA3 指纹库:查询已知指纹(JA3er)
TLS 指纹识别是一种强大的技术,可用于识别和分类网络流量。了解 JA3/JA4 的工作原理对于安全分析和防御都很重要。通过合理配置 TLS 参数,可以减少指纹的唯一性,降低被识别的风险。
参考来源#