客户端指纹
前言
不知道大家有没有遇到这种场景,我无痕方式访问某个网站,该网站依然能够精准对我进行个性化推荐?这是为什么呢?接下来,本文将介绍客户端指纹有关知识点
浏览器指纹
什么是浏览器指纹?
浏览器指纹是一种用于识别用户设备的浏览器的唯一标识符。它通过收集设备和浏览器的各种信息,如用户代理、屏幕分辨率、字体、插件列表等,以创建一个唯一的标识符。浏览器指纹可用于多种用途,包括用户身份验证、设备追踪和数据分析。
fingerprint
我们打开 fingerprint 网站 ,可以看到在正常和无痕模式下,指纹都是唯一的 开源库:https://github.com/fingerprintjs/fingerprintjs (opens in a new tab)
正常模式:
无痕模式:
可以看到你在正常模式和无痕模式下访问的时长都被记录了下来
fingerprintjs 的工作原理
-
信息收集:浏览器指纹技术通过收集用户设备和浏览器的各种信息来创建唯一标识。这些信息可以包括用户代理字符串、屏幕分辨率、操作系统、字体列表、插件列表、硬件配置等等。
-
信息组合:收集到的信息会经过一定的处理和筛选,以便生成稳定的浏览器指纹。通常,某些信息会被排除,而其他信息会被加入到最终的指纹中。
-
信息哈希化:一旦收集到足够的信息并形成了浏览器指纹的基础数据,这些数据将被组合在一起,并经过哈希函数的处理,生成一个唯一的哈希值。这个哈希值就是用户的浏览器指纹。
-
指纹存储:生成的浏览器指纹通常会被存储在用户设备上,通常是在浏览器的本地存储(如 localStorage)中。这样,网站可以在用户下次访问时检查指纹,以进行身份验证或个性化推荐等操作。
-
指纹比对:当用户再次访问网站时,网站会请求并获取浏览器指纹信息,然后将其与之前存储的指纹进行比对。如果两个指纹匹配,网站就可以确认这是同一用户。
TLS 指纹
什么是 TLS 指纹?
TLS 指纹是一种用于识别和验证 TLS(传输层安全)通信的技术。
TLS 指纹可以通过检查 TLS 握手过程中使用的密码套件、协议版本和加密算法等信息来确定 TLS 通信的特征。由于每个 TLS 实现使用的密码套件、协议版本和加密算法不同,因此可以通过比较 TLS 指纹来判断通信是否来自预期的源或目标。
TLS 指纹可以用于检测网络欺骗、中间人攻击、间谍活动等安全威胁,也可以用于识别和管理设备和应用程序。
TLS 指纹识别原理(ja3 算法):https://github.com/salesforce/ja3 (opens in a new tab)
测试 TLS 指纹
测试网站:https://tls.browserleaks.com/json (opens in a new tab)
- curl
- Chrome Version 119.0.6045.123 (Official Build) (arm64)
- Firefox
- Python
可见不同的客户端都存在区别,针对最后一个 python 的 ja3_text 做一个简单的说明
第一个值 771
:表示 JA3 版本,即用于生成指纹的 JA3 脚本的版本。
第二个值 4866-4867-4865-49196-49200-49195-49199-52393-52392-49188-49192-49187-49191-159-158-107-103-255
:表示加密套件,即客户端可以支持的加密算法。
第三个值 0-11-10-16-22-23-49-13-43-45-51-21
:表示支持的压缩算法。
第四个值 29-23-30-25-24-256-257-258-259-260
:表示支持的 TLS 扩展,如 SNI。
第五个值 0-1-2
:表示支持的 elliptic curves,即椭圆曲线算法。
Akamai 指纹相关(HTTP/2 指纹)
什么是 Akamai 指纹?
Akamai Fingerprint 是 Akamai Technologies 公司提供的一种防止恶意机器人和自动化攻击的技术,它基于浏览器指纹识别技术。
浏览器指纹是一种用于识别 Web 浏览器的技术,它通过收集并分析浏览器的各种属性和行为,如用户代理字符串、插件、字体、语言、屏幕分辨率等信息来识别浏览器。浏览器指纹在互联网安全领域得到了广泛应用,可以用于检测和识别恶意机器人、欺诈行为、网络钓鱼等。
Akamai Fingerprint 利用了浏览器指纹技术,将其与其他安全技术结合起来,以识别和拦截自动化攻击。它可以在不影响用户体验的情况下,对访问网站的浏览器进行识别和验证,防止自动化攻击、账户滥用和数据泄露等安全问题。
可以在 https://tls.peet.ws/api/all (opens in a new tab) 看到详细的指纹,主要有如下内容
指纹为: 1:65536,2:0,4:6291456,6:262144|15663105|0|m,a,s,p
生成方式:对 HTTP/2 中的 4 种 frame 采样,分别是:SETTINGS、WINDOW_UPDATE、PRIORITY、HEADERS,它们间使用“|”隔开,
SETTINGS|WINDOW_UPDATE|PRIORITY|HEADERS
-
SETTINGS 部分:对发送的 settings 编码,格式
KEY:VALUE
,多个逗号隔开。其中HEADER_TABLE_SIZE
的KEY=1``、ENABLE_PUSH
的KEY=2
、MAX_CONCURRENT_STREAMS
、INITIAL_WINDOW_SIZE
、MAX_FRAME_SIZE
、MAX_HEADER_LIST_SIZE
以此类推。 -
WINDOW_UPDATE 部分:若存在该 frame,则编码为
increment
值,否则00
-
PRIORITY 部分:若存在该 frame,则编码为
stream:exclusive:dependsOn:weight
,否则0
-
HEADERS 部分:以 : 开头的 header 的第一个字符参与编码,多个逗号隔开。如
:method
、:scheme
编码为m,s
所以我们上面的指纹就为:
-
1:65536
:HEADER_TABLE_SIZE
,即头部表大小为 64KB,指的是用于存储请求头和响应头的大小,它是可以调整的。这个字段指明了使用 64KB 的头部表大小。 -
2:0
:HTTP2_VERSION
,指示此请求使用的 HTTP/2 版本。0 表示 H2,表示启用了 HTTP/2 协议。 -
4:6291456
:INITIAL_WINDOW_SIZE
,即初始流窗口大小,指的是初始的流控窗口大小,即客户端可以发送的最大字节数量。这个字段指明了初始流窗口大小为 6MB(即 6291456 字节)。 -
6:262144|15663105|0|m,a,s,p
: 以竖杠“|”分隔。具体含义如下:-
6:262144
:max header list size
,即动态表大小,指的是接收方可以接收的最大 HTTP 头部大小。这个字段指明了动态表大小为 256KB(即 262144 字节)。 -
15663105
:WINDOW_UPDATE
,表示收到了 WINDOW_UPDATE 帧,并且窗口大小增加了 15663105 个字节。 -
0
:no compression
,表示不启用头部压缩。
-
-
以
:
开头的header
的第一个字符参与编码,多个逗号隔开。:method
、:authority
、:scheme
、:path
编码为m,a,s,p
可在 Passive Fingerprinting of HTTP/2 Clients (opens in a new tab) 中查看详细细节
绕过 TLS 指纹
使用成熟的库伪造指纹进行请求,例如 Python 的 curl_cffi (opens in a new tab) ...
https://ascii2d.net/ (opens in a new tab) 就存在 cloudflare 的指纹护盾,拒绝爬虫,可以伪造请求进行测试
绕过:
from curl_cffi import requests
req = requests.get("https://ascii2d.net", impersonate="chrome110")
print(req.text)