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 参数,可以减少指纹的唯一性,降低被识别的风险。


参考来源