fingerprint-js-Pro采集项分析

fingerprint.js Pro v3,近100多个采集项,只有压缩无混淆,直接开干
有几个stage2的条目挺奇怪的,里面的解密函数在chrome138上跑不起来,其余均分析完毕

总览

根据文档用这个脚本直接从cdn上把他的脚本文件拉下来,所有的代码都在fYicOuiT1WRGwuZgAESv.js这个文件里,小7000行还算ok,只有压缩无混淆,用prettier格式化后还算能看,大部分工作量在重命名压缩后损失的符号,先总体看下业务逻辑

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>FingerprintJS Example</title>
</head>
<body>
<h1>FingerprintJS Example</h1>
<script>
// Initialize the agent on page load.
const fpPromise = import('https://fpjscdn.net/v3/fYicOuiT1WRGwuZgAESv')
.then(FingerprintJS => FingerprintJS.load({
region: "ap"
}))

// Get the visitorId when you need it.
fpPromise
.then(fp => fp.get())
.then(result => {
const visitorId = result.visitorId
console.log(visitorId)
})
</script>
</body>
</html>

这个一个巨大的字典序列一看就是采集项,先看看这玩意怎么跑起来的

导出的函数是load,可以看到load里填充了一下配置项,然后就是跑服务

这里前面做了一大堆初始化,就不展示了,initSandbox是初始化了一个iframe,因为有些测试项需要添加DOM元素,所以需要在隔离的iframe里做

这里看到就是把module里的stage拆出来然后开始准备跑

这里就可以看到,stage里是一堆函数,然后并发的调用了这些函数,注意到这个context是传给stage[e]的第一个参数(用bind绑定),这点非常重要,因为这样后面分析每个采集函数时遇到的不知道什么类型还找不到引用的参数基本都可以确定是是这里的context,然后就可以去runService里找上下文里填充了什么对象,根据对象名判断到底调了浏览器里的什么东西

也就是说那个stage列里面是一堆worker函数,那一个个函数看过去就好了

总表

Stage1

项目ID 函数名 实际功能
s94 ia tls支持检测,似乎tls指纹检测在服务端

Stage2

项目ID 函数名 实际功能
s52 pc voiceInfoHash 获取浏览器语音支持信息
s6 Ki ScreenSize 页面尺寸信息
s58 Rc PlatformInfoFromList 测试一些平台信息
s20 lc Font 测试字体支持
s36 Ji has_AdBlocker 测试有没有广告拦截插件
s51 zi test_font_width 测试字体宽度
s21 qi audio_data 采集浏览器音频数据指纹
s79 Wc
s69 Sc IframeUrl 逐层遍历iframe到顶层并获取各层url
s23 us webkitRequestFileSystem 测试webkitRequestFileSystem是否可用
s29 is storageQuota 获取当前域名分配的储存空间
s84 ss Sandbox_Iframe_width_height 获取iframe沙箱的宽高
s85 ds test_indexDB 测试indexDB能否正常储存
s89 Pc storage.getDirectory 测试storag.getDirectory()能否调用
s17 du canvas_test 测试Canvas指纹和支持
s87 Vs system_color 测试系统颜色支持
s92 Zs mathML 测试mathML数学符号支持
s93 Ds emoji 测试emoji符号支持
s95 Ea
s97 Aa
s70 Fa

Stage3

项目ID 函数名 实际功能
s22 Hc wasm 测试wasm相关功能是否支持
s30 Zc doNotTrack 检查doNotTrack属性
s33 ec Brave Brave浏览器
s44 oc theme_color 颜色主题
s45 uc Time 获得用户本地时间与UTC时间的差值
s49 dc PerformanceIntervals 获取设备时间戳精度
s50 vc jsHeapSizeLimit 获取js堆大小
s57 Uc devicePixelRatio
s59 Yu IE 检查IE浏览器相关属性是否存在
s60 Xu Edge 检查Edge浏览器相关属性是否存在
s61 Ju Chrome
s62 zu Apple 是否为apple平台
s63 qu Safari
s64 Ku Firefox
s65 Qu mobile 是否为移动平台
s66 Cu attributionSourceId 测试<a></a>中的这个属性
s68 nc new_api 测试几个特定api
s71 Ac origin 检测页面来源链接
s24 Lc get_eval_toString_length 对eval调用toString然后获取结果的长度
s72 Cc webdriver 典中典属性
s1 Qi oscpu 架构属性(现代多数弃用)
s2 nu language 语言列表
s3 tu colorDepth 屏幕色深
s4 eu deviceMemory 获取设备内存近似值
s5 ru height_width 获取屏幕宽高
s7 ou hardwareConcurrency 获取设备线程数
s9 iu timezone 获取时区
s10 uu sessionStorage 测试相应api是否为null
s11 cu localStorage 测试相应api是否为null
s12 ls has_indexedDB 测试相应api是否为null
s13 su openDatabase 测试相应api是否为null
s14 au get_cpuClass_
s15 lu is_ipad_or_iphone_
s16 fu plugins
s19 mu touch_event 测试touchEvent是否可用
s27 vu vendor 获取vendor属性
s28 hu vendor_keys 获取一些和平台相关的key
s32 pu cookie 测试cookie是否开启
s37 gu color_gamut 测试色域
s41 wu invert_color 测试反色是否开启
s39 yu force_color 测试是否强制使用某颜色设置
s42 bu monochrome 获取色深
s38 Eu perfer_contrast 获取对比度偏好
s43 Ru motion_set 获取动画设置
s40 Iu dynamic_range_set 获取色彩范围
s46 ku Math_func_test_hash 测试三角函数和对数相关的函数返回值
s80 Au pdfViewerEnabled
s81 Lu NaN_imply 获取NaN的内存表示
s82 rs language_ 又调了一次上面的获取语言的函数。。
s83 os language_ 连在一起还调用了一次。。
s86 vs no_storage 似乎是测试是否禁用本地储存
s91 Su transparency_set 获取透明度设置
s96 Pu AudioLatency 获取音频处理的AudioLatency属性
s98 La serviceWorker 检查属性
s99 Ca isSecureContext 检查属性
s200 Za timeStamp 获取一个时间戳
s201 tc new_web_api 测试几个api
s202 _u locale 似乎是获取地区
s74 Tu webgl_context_info 获取webgl信息
s75 Ou webgl_infos 其他的webgl信息
s76 hc webgl_render_data 测试webgl渲染指纹

其他参数

还有一些参数不在stage里面,看了看似乎也和采集关系不大

项目ID 函数名 实际功能
s55 nl 获取本地存储和cookie中的_vid_t值
s48 gc 获取一段伪随机序列

tls项似乎是自实现的tls传输函数,用来上传数据的

stage2

stage1只有一个项目,而且非常的长,不知道是什么,先看stage2

voiceInfoHash


这里是从window中获取浏览器语音序列,然后由r这个函数转换成json再转字符串后调murmurhash3转换成哈希值

注意到这里如果获取不到语音序列(speechSynthesis没有addEventListener成员,推测是为了防止一些指纹浏览器内置一个空的speechSynthesis)会调用两个属性检查函数,暂时没发现这两组属性有啥联系

ScreenSize

这个函数比较简单,就是测一下窗口尺寸和是否全屏

getPlatformInfoFromList

这个函数获取一些UA和平台信息

主要拿以下几个key

Font


这个函数对列表里预置的字体进行测试,他有一个CSS标准字体列表和测试字体列表,通过比对测试字体和标准字体渲染出的文字的实际宽高是否不同来对比浏览器是否支持对应字体

has_AdBlocker

这个函数测试用户是否安装了某几个广告拦截器
测试方法是先收集了一些广告拦截器默认会拦截的DOM元素属性,然后添加含这些属性的元素,再检查这几个元素的parentNode属性(如果被广告拦截器删掉的话parentNode会为null)

test_font_width

这个函数前面又把生成iframe沙箱的逻辑重写了一遍,直接看下面传给沙箱的函数

这里还是比较简单的,就是选择了几个字体,然后测试了他们的宽度

audio_data

这个函数生成了一段测试音频,然后对其采样值的前4500个数据的绝对值求和作为浏览器指纹的参考数据

IframeUrl

这个函数从这个页面所在的iframe开始尝试逐层向上遍历iframe嵌套结构并获取每一层iframe的url,应该是为了识别当前页是否被嵌套

webkitRequestFileSystem

这个函数通过在webkitRequestFileSystem申请1字节内存;来测试api是否可用


如果是检测到较新版本chrome则不测试,可能是因为新版本chrome弃用了这个api

storageQuota

尝试从webkitTemporaryStoragestorage两个成员中获取储存空间大小信息

Sandbox_Iframe_width_height

获取iframe的宽高,有点意味不明

test_indexDB

随机创建的一个indexDB并尝试储存一个数据(似乎前提是要先检测到为safari或firefox浏览器)

storage_getDirectory

测试storage.getDirectory方法能否调用

canvas_test

测试canvas指纹

system_color

在沙箱里生成一堆不同颜色的div测试系统颜色支持

mathML

生成一些数学公式并测试符号的渲染情况

emoji

测试浏览器emoji图案支持

stage3

wasm

5段测试demo测试不同的wasm功能,然后通过bitmask保存测试结果

doNotTrack

直接获取doNotTrack属性

Brave

测试是否为Brave浏览器(似乎是国外的一种隐私浏览器)并测试是否开启随机canvas指纹功能

theme_color

测试用户颜色主题

Time

计算用户本地时间和utc时间的差值

PerformanceIntervals

连续调用window.performance.now(),记录间隔时间中最小和次小的获取设备时钟精度

jsHeapSizeLimit

获取堆大小

devicePixelRatio

获取devicePixelRatio属性的值

IE

检查了几个微软开头的key

Edge

这个应该是检查Edge,并且和IE区别开了

Chrome

检查chrome浏览器

Apple

测试apple平台的标签

Safari

测试safari浏览器

Firefox

测试firefox浏览器

mobile

测试是否为移动平台

attributionSourceId

测试attributionSourceId属性,但是chrome138上没找到这个属性

new_api

测试几个比较新的api(存疑),暂时没出来这个几个api有什么共性,有几个看着是跟隐私相关的(geolocation webRTC)

origin

获取当前页面来源及其父级来源,大概可以检测嵌入之类的

eval_toString_length

对eval调用toString然后获取结果的长度,据说不同js引擎这个返回值都是不一样的

下面是claude 4.0 给出的例子

1
2
3
4
5
6
7
8
// Chrome/V8
eval.toString() // "function eval() { [native code] }"

// Firefox/SpiderMonkey
eval.toString() // "function eval() {\n [native code]\n}"

// Safari/JavaScriptCore
eval.toString() // "function eval() { [native code] }"

webdriver

简单直接,直接获取webdriver属性

oscpu

获取oscpu属性,似乎现代浏览器不少都弃用了这个api

language

获取浏览器语言列表

colorDepth

获取屏幕色深

deviceMemory

获取设备内存近似值

height_width

获取屏幕宽高(stage2还有个类似的函数,那个是返回屏幕边距的)

hardwareConcurrency

获取设备线程数

timezone

获取设备时区

sessionStorage,localStorage,indexedDB,openDatabase

这几个都是测试api是否为Null

cpuClass

获取cpuClass属性,chrome138上无

is_ipad_or_iphone

似乎是根据宽高比判断是ipad还是iphone

plugins

获取内置插件列表,也是典中典了

touch_event

获取最多触点数以及touchEvent是否可用

vendor

获取浏览器厂商标签

vendor_keys

匹配一些和厂商相关的标签

测试是否开启cookie

color_gamut,invert_color_,force_color_,monochrome_test,perfer_contrast_,motion_set_,dynamic_range_set_,transparency_set_

这些都是和画面设置相关的参数获取

Math_func_test_hash

测试三角函数和对数函数,并将结果hash保存

pdfViewerEnabled

如图

NaN_imply

获取NaN的具体内存表示(似乎不同的js引擎实现这个值是不同的)

no_storage

似乎是测试是否禁用本地储存,有一个属性在win上获取不到

AudioLatency

获取AudioLatency属性

serviceWorker

检查serviceWorker是否存在

isSecureContext

检查isSecureContext的值

timeStamp

获取一个时间戳

new_web_api

没看懂这几个api之间的关联

locale

获取语言地区

webgl_context_info

获取webgl信息,渲染驱动,厂商之类的

webgl_infos

获取一些别的webgl相关的信息用于生成指纹

webgl_render_data

运行一小段渲染程序获取当前webgl引擎的渲染指纹

注释版的采样代码

fYicOuiT1WRGwuZgAESv.js

Author

SGSG

Posted on

2025-09-09

Updated on

2025-09-16

Licensed under