目录
前文
前几天第一次接触到ja3,十分的好奇。经过今天几天的研究和学习,发现了点东西,记录下。另外下篇会分享自己用php撸的ja3获取工具。
另外本文将https://ja3er.com/form简称为ja3er。
ja3_Hash获取规则
- 场景
tls clint hello,准确的说是:- 字节 0:值 22,表示根据 TLS 规范的“握手”。
- 字节 5:根据 TLS 规范,值 1,在握手包内指示客户端问候。
- 字节 9:值 3,两个字节中的第一个字节,与任何版本的 TLS 对齐的 TLS 版本。如果匹配 SSL,该值也可能为 0。
- 字节 1:与字节 9 相同,但与记录 TLS 版本有关”
- 字段顺序
TLSVersion,Ciphers,Extensions,EllipticCurves,EllipticCurvePointFormats - 拼接规则
按顺序连接在一起,使用“,”分隔每个字段,使用“-”分隔每个字段中的每个值。 - MD5 哈希处理
拼接后的ja3_str经过MD5处理得到ja3_hash - 忽略的值,该值在Ciphers,Extensions,EllipticCurves会出现
GREASE
具体为:
$GREASE_TABELE = [
2570,//(0x0A0A)
6682,//(0x1A1A)
10794,//(0x2A2A)
14906,//(0x3A3A)
19018,//(0x4A4A)
23130,//(0x5A5A)
27242,//(0x6A6A)
31354,//(0x7A7A)
35466,//(0x8A8A)
39578,//(0x9A9A)
43690,//(0xAAAA)
47802,//(0xBABA)
51914,//(0xCACA)
56026,//(0xDADA)
60138,//(0xEAEA)
64250,//(0xFAFA)
];
发现
忽略的扩展
ja3er 中的ja3_str会把类型值为17513的扩展忽略掉
Type: application_settings (17513)
例子:
// from ja3er
……27-21,29-23-24,0
// from mycode
……27-17513,29-23-24,0
变化的ja3
与curl 不同,ja3_str 在chrome中是2个值
//第一次访问时是一个值
……27-17513-21,29-23-24,0
// 之后的访问是另外一个值
……27-17513,29-23-24,0
主要是取决于场景,在chrome中
-
首次访问session_ticket为空
此时会增加一个拓展,名为padding,类型值为21Type: padding (21)
-
之后访问session_ticket有值
此时没有padding扩展
这个情况在ja3er和我的代码中都会出现,应该是tls session 机制导致。ja3er中比较难复现,可以尝试用无痕。
关于Wireshark的JA3
示例数据:
[JA3 Fullstring: 771,10794-4865-4866-4867-49195-49199-49196-49200-52393-52392-49171-49172-156-157-47-53,60138-0-23-65281-10-11-35-16-5-13-18-51-45-43-27-17513-31354,23130-29-23-24,0]
[JA3: 432d80490caf1b032a7e091754f2f597]
如果你也有测试,你会发现在Wireshark中,JA3不是固定的。原因很简单,它并没有忽略GREASE。如实例中,771,10794-4865 中的 10794,正是10794,//(0x2A2A)。
nginx几个与ja3相关的变量
只测试了本地和我的服务器,仅供参考
nginx 配置
location ~ \.php(.*)$ {
fastcgi_param ssl_protocol $ssl_protocol;
fastcgi_param ssl_curves $ssl_curves;
fastcgi_param ssl_cipher $ssl_cipher;
fastcgi_param ssl_ciphers $ssl_ciphers;
fastcgi_param ssl_server_name $ssl_server_name;
fastcgi_param ssl_client_fingerprint $ssl_client_fingerprint;
fastcgi_param ssl_session_id $ssl_session_id;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_split_path_info ^((?U).+\.php)(/?.+)$;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;
include fastcgi_params;
}
php代码
var_dump(__FILE__.' line:'.__LINE__,$_SERVER);exit;
结果
- 数据示例
["ssl_session_id"]=>
string(64) "8ba7742fd5a32ddb4c842aa34ce97325cd19015720389ff8c04650e049be4b75"
["ssl_client_fingerprint"]=>
string(0) ""
["ssl_server_name"]=>
string(5) "xxx.com"
["ssl_ciphers"]=>
string(355) "0xcaca:TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA:AES256-SHA"
["ssl_cipher"]=>
string(27) "ECDHE-RSA-AES256-GCM-SHA384"
["ssl_curves"]=>
string(0) "0x1a1a:X25519:prime256v1:secp384r1"
["ssl_protocol"]=>
string(7) "TLSv1.2"
- 对比
变量 | ssl_protocol | ssl_curves | ssl_cipher | ssl_server_name | ssl_client_fingerprint | ssl_session_id |
---|---|---|---|---|---|---|
首次访问 | Y | Y | Y | Y | empty | empty |
后续访问 | Y | empty | Y | Y | empty | Y |
- 发现
- ssl_session_id 并不是固定值,每次请求都会变化。
- ssl_session_id存在时会与Wireshark抓到的一致,也就是时传递过来的,不太懂为啥第一次就没有。
Session ID: 8ba7742fd5a32ddb4c842aa34ce97325cd19015720389ff8c04650e049be4b75
- 首次访问时,与jas_str字段差距只是缺少Extensions。或许可以作为一个简化版的ja3。
TLSVersion,Ciphers,
Extensions,EllipticCurves,EllipticCurvePointFormats
SNI 真的很好取
备案检测是怎么做到的?,另外了解到,ie部分版本是不支持SNI,也就是你可以用它上未备案的网站,然而这没卵用。具体支持情况: