JA4指纹了解

原文来自:https://mp.weixin.qq.com/s/Vo57J6l7WEt7L2bF_EAfbA

https://xz.aliyun.com/t/14054?time__1311=mqmx9DBG0QD%3DNGNDQiiQGk0G8UAfWRi8rD&alichlgref=https%3A%2F%2Fwww.baidu.com%2Flink%3Furl%3DiCpL-H6nh6F3hHSqKNxdmugqoq3VxxR00WtgPIO6P2n4QKqCs9QZmOV5veTiylJY%26wd%3D%26eqid%3Db1fbca78000a6958000000066660296f

开源链接是:

https://github.com/FoxIO-LLC/ja4

ja4概述文章是:

https://blog.foxio.io/ja4-network-fingerprinting-9376fe9ca637

在 TLS 连接开始时,客户端会发送一个 TLS 客户端 Hello 数据包,该数据包在加密通信之前以明文形式发送。此数据包由客户端应用程序生成,用于通知服务器它支持的密码以及其首选的通信方式。因此,TLS 客户端 Hello 数据包对于每个应用程序或其底层 TLS 库都是唯一的

无论流量是通过 TCP 还是QUIC传输,JA4 都会对客户端进行指纹识别。QUIC 是新 HTTP/3 标准使用的协议,它将 TLS 1.3 封装到 UDP 数据包中。由于 QUIC 是由 Google 开发的,如果某个组织大量使用 Google 产品,QUIC 可能占其网络流量的一半,因此捕获这一点非常重要。

JA4 还清楚地显示了 ALPN(应用层协议协商)。这表示应用程序在 TLS 协商完成后想要通信的协议。“h2”= HTTP/2,“h1”= HTTP/1.1,“dt”= DNS-over-TLS 等。可能的 ALPN 的完整列表可在此处找到。此处的“00”表示缺少 ALPN。请注意,ALPN“h2”的存在并不表示浏览器,因为许多 IoT 设备通过 HTTP/2 进行通信。但是,缺少 ALPN 可能表示客户端不是 Web 浏览器。

有关实施的更多技术细节以及原始(未散列)指纹的样子可以在github 页面上找到。

客户端发送其 TLS 客户端问候数据包后,服务器将使用其 TLS 服务器问候数据包进行响应。此数据包也以明文形式发送,根据服务器在客户端问候中选择的可用选项制定。这包括从可用选项列表中选择的一个密码,以及服务器希望设置的任何扩展。

因此,Server Hello 对于服务器应用程序和发送给它的 Client Hello 都是唯一的。不同的 Client Hello 可能会导致来自同一服务器的不同 Server Hello,因此也会导致不同的 JA4S。但是,相同的 Client Hello 始终会从该服务器应用程序产生相同的 Server Hello。例如,如果客户端发送 JA4=a_b_c 并且服务器以 JA4S=d_b_e 响应,则该服务器将始终以 d_b_e 响应 a_b_c。但是,如果另一个应用程序向同一服务器发送不同的客户端 hello,例如 JA4=x_y_z,则服务器将以不同的服务器 hello JA4S=t_y_v 响应。因此,对不同的应用程序来说,响应不同,但对同一应用程序来说,响应始终相同。我在我的JA3S 博客文章中对此进行了更详细的介绍

JA3 的结构

TLSVersion,Ciphers,Extensions,EllipticCurves,EllipticCurvePointFormats

相同与不同

相同

  1. 关注 TLS version
  2. 关注 cipher suite
  3. 关注 TLS extension

不同

JA4不关心的

  1. EllipticCurves
  2. EllipticCurvePointFormats

增加的

  1. IP Protocol,
    用于标记TCP 或 QUIC,用 t 和 q 表示

  2. TLS version
    不同于JA3,JA4会尝试在拓展中找到可支持的最高TLS version。
    指纹中代表字符串映射关系如下:

    $ssl_version = [ 0x0100 => "s1", 0x0200 => "s2", 0x0300 => "s3", 0x0301 => "10", 0x0302 => "11", 0x0303 => "12", 0x0304 => "13", 0x00 => "00", ];
  3. SNI (Server Name Indication)
    如果该拓展类型是域名(domain)记为 ‘d’,否则为’i’

  4. number of Cipher Suite

  5. number of Extensisions

  6. ALPN (Application-Layer Protocol Negotiation)
    取应用层协议协商拓展的第一个值,如果没有则用 00表示。
    具体算法如下

    // $tls_tls_handshake_extensions_alpn_str = ['h2','http/1.1']; h2 // $tls_tls_handshake_extensions_alpn_str = ['h3','http/1.1']; h3 // $tls_tls_handshake_extensions_alpn_str = ['http/1.1']; h1 // $tls_tls_handshake_extensions_alpn_str = ['http/1.0']; h0 $first_ALPN = current($tls_tls_handshake_extensions_alpn_str); if (strlen($first_ALPN) > 2) { $first_ALPN = substr($first_ALPN, 0, 1).substr($first_ALPN, -1, 1); } else { if (strlen($first_ALPN) > 127) { $first_ALPN = '99'; } }
  7. Cipher Suite sroted
    相比JA3,JA4会将Cipher Suite进行排序,同样忽略 GREASE_TABEL类型的拓展

  8. Extensisions sroted
    相比JA3,JA4会将Extensisions进行排序,忽略 GREASE_TABEL类型的拓展,同时会再忽略JA4_a中的SNI,ALPN拓展

  9. Signature Algorithms,in the order they appear
    签名哈希算法(准确的说:拓展signature_algorithms(13),按出现的顺序。

    注意:在firefox中,会有拓展delegated_credential(34),也是一个提供Signature Algorithms的拓展,但计算JA4时应该忽略,具体看JA4 is including signature hash algorithms outside of the signature hash extension

常见的JA4

browerJA4mark
Chrome/121 t13d1516h2_8daaf6152771_02713d6af862  
Chrome/121 t13d1517h2_8daaf6152771_b1ff8ab2d16f no key
Chrome/121 13d1517h2_8daaf6152771_b0da82dd1658 with pre_share_key
Edg/122 t13d1516h2_8daaf6152771_02713d6af862  
Edg/122 t13d1517h2_8daaf6152771_b0da82dd1658 with pre_share_key
Firefox/123.0 13d1715h2_5b57614c22b0_5c2c66f702b0  
Firefox/123.0 13d1715h2_5b57614c22b0_7121afd63204 with pre_share_key
OPR/102 t13d1516h2_8daaf6152771_e5627efa2ab1  
OPR/102 t13d1516h2_8daaf6152771_9b887d9acb53 with pre_share_key
curl/7.68.0(ubuntu) t13d3113h2_e8f1e7e78f70_ce5650b735ce  
curl/8.4.0(win10) t12d2109h1_76e208dd3e22_7af1ed941c26  
iPhone OS 16_4_1 Safari 13d2014h2_a09f3c656075_14788d8d241b

 

 

什么是 QUIC

对于用户侧来说 QUIC 主要解决的是延迟的问题,这里我们主要说一下它和 TCP 的区别,简单来说,QUIC 进行了一次 “资源整合”,它把之前 HTTP/2、TLS、TCP 三者的优势集合起来

由于 QUIC 已经整合了这些内容,那么让它继续工作在 HTTP/2 下会出现许多问题,所以便催生了 HTTP/3,因为 QUIC 本身是要取代 TCP 的,所以它的传输层协议选择的是 UDP

 

 

JA4 计算原理

 

JA4 计算的是 Client Hello 报文,这里以官方给出的 Chrome JA4 指纹作为样例来进行演示JA4=t13d1516h2_8daaf6152771_02713d6af862,分成 JA4_a、JA4_b、JA4_c 三部分,计算的大原则是:按照规定顺序排列,忽略所有 GREASE 值

 

JA4_a

 

  • t:代表 TCP,此位置代表协议,还有q,代表 QUIC
  • 13:代表 TLS Version,这里代表 1.3,更多情况请见下表
    0x0304 = TLS 1.3 = “13”  
    0x0303 = TLS 1.2 = “12”  
    0x0302 = TLS 1.1 = “11”  
    0x0301 = TLS 1.0 = “10”  
    0x0300 = SSL 3.0 = “s3”  
    0x0200 = SSL 2.0 = “s2”  
    0x0100 = SSL 1.0 = “s1”
    Unknown = “00”

 

当我们仔细观察抓到的包时,可以发现有些包 WireShark 显示的是 TLS 1.2 但 JA4_a 中给出的却是 13,这并不是计算上的错误,是因为 JA4 计算时实际上读取的是数据包中的最高版本

 

出现 TLS Version 的部分一共有三个部分,上面出现 13 的原因就是在拓展(Extension)中有一项supported_version存在 TLS 1.3

 

 d:代表 Domain,这里的判断依据是 SNI Extensions,如果它存在则访问的是域名,不存在则说明访问的是 IP,此时为i

 

  • 15:代表 Cipher Suites 的数量,即便是单数也选择两位输出,例如 6 个就是06,最大值显示到99,忽略 GREASE 值
  • h2:代表 ALPN 值,选取第一个值,更多情况见官方文档,若报文中没有此项,则使用00

ALPN 主要负责应用层协议的协商,浏览器发送 Client Hello 报文时同时提供两种选项,若服务器支持 HTTP/2 则选择 h2,如果不支持,则从客户端支持的协议列表中选取一个它支持的协议,一般情况下选择 HTTP/1.1,体现在 JA4 指纹中就是h1

JA4_b

JA4_b 的计算根据是 Cipher Suite 值,使用,分隔不同字段(忽略 GREASE 值),但是会进行一个从小到大的排序,例如

1301,1302,1303,c02b,c02f,c02c,c030,cca9,cca8,c013,c014,009c,009d,002f,0035

按照从小到大的排序原则处理后,变为

002f,0035,009c,009d,1301,1302,1303,c013,c014,c02b,c02c,c02f,c030,cca8,cca9

对这串数据再进行 SHA256 加密,最终截取加密后字符串(小写)的前 12 位,组成 JA4_b

8daaf6152771e33e12d734f9bc6478ed341f16cde27aee3aa36f2402f2c53b44

JA4_b = 8daaf6152771

这里排序的意义在于降低 “Cipher Stunting“ 的影响,关于什么是 “Cipher Stunting“ 请见【JA3 优化】部分,但是并不是说顺序不重要,这里是为了保真度所做的取舍,作者给出的原因是,在研究时发现大多数应用使用的是独特的 Cipher,而不是独特的 Cipher Suite 排序(It does but in our research we’ve found that applications and libraries choose a unique cipher list more than unique ordering)

JA4_c

JA4_c 的计算根据是 Extensions-Type 值,忽略 GREASE 值、SNI 扩展名(0000)、ALPN 扩展名(0010),这里使用的是 Extensions-Type 值的十六进制格式(不含0x

 

 

例如以下原始数据

001b,0000,0033,0010,4469,0017,002d,000d,0005,0023,0012,002b,ff01,000b,000a,0015

经过排序后(从小到大,同时去除00000010

0005,000a,000b,000d,0012,0015,0017,001b,0023,002b,002d,0033,4469,ff01

这里的排序目的和 JA4_b 类似,但主要对抗的是 Extension 随机化问题,例如 Google 在 2023 年更新了 Chrome,主要实现的就是随机化 Extension,避免开发者过于依赖此功能

 之后会再读取一个 Extension 中 signature_algorithms(签名算法) 的值,同样使用,作为分隔符

 

这里直接使用默认排序

0403,0804,0401,0503,0805,0501,0806,0601

最后将两串字符串合二为一,中间使用_分隔,处理后的 Extensions-Type 在前,未处理的 signature_algorithms 在后

0005,000a,000b,000d,0012,0015,0017,001b,0023,002b,002d,0033,4469,ff01_0403,0804,0401,0503,0805,0501,0806,0601

对这串数据再进行 SHA256 加密,最终截取加密后字符串(小写)的前 12 位,组成 JA4_c

e5627efa2ab19723084c1033a96c694a45826ab5a460d2d3fd5ffcfe97161c95

JA4_c = e5627efa2ab1
posted @ 2024-06-05 17:31  冰糖葫芦很乖  阅读(506)  评论(0编辑  收藏  举报