NOTICE: By continued use of this site you understand and agree to the binding مەرجەکانی خزمەتگوزاری and سیاسەتی پاراستنی نهێنی.
Install steps: Install a userscript manager, select Install, then open a website matched by the script.
The following figures come from the original source and are separate from activity on this site.
Original script: 轻量级浏览器指纹 & 追踪防御盾
Source version: 1.7
Last source check:
Last successful check:
Requests received by this site are not proof that a user completed installation.
Clicking Install records a request on this site; it does not confirm installation. Not working after install? View troubleshooting and issues
即使清除了 Cookie、打开了无痕窗口,网站仍有办法认出你。画布(Canvas)上所绘图像的细微像素差异、音频处理的结果、GPU 名称、CPU 核心数等数值组合在一起,就构成了能识别你浏览器的“指纹”(fingerprint)。而且与 Cookie 不同,指纹无法删除。
本脚本会为从画布、WebGL、WebGPU、WebCodecs 和音频中读取的数值,以及画布文字尺寸(measureText),加入每次打开页面时重新选定、看不见也听不到的噪声。由这些值生成的指纹每次打开都会不同,因此无论在网站之间还是在各次访问之间,都很难把它们关联起来。像 GPU 名称、核心数这样在本脚本无法触及的地方(Worker、请求头等)也能读到的数值,本脚本特意不作修改。这是因为,如果只在窗口中修改,数值就会彼此矛盾,而这种矛盾反而会成为痕迹。
噪声由脚本启动时用 crypto.getRandomValues 新生成的 32 位密钥决定。同一页面内密钥不变,因此同一图像无论读取多少次、读取局部还是全部、用何种方式读取,得到的值都相同;而刷新、打开新标签页或再次访问时会使用新密钥,因此包含画布和音频数值的指纹哈希会随之改变。例如,FingerprintJS 5.2.0 开源版在 Chromium 内核浏览器上会把画布和音频数值也纳入访客哈希,因此该哈希应当也会在每次打开页面时改变(这是根据源代码得出的判断,并未与本脚本一起实际运行过)。
| 阻止读取的方式 | 每次随机改变的方式 | 本脚本 | |
|---|---|---|---|
| 使用画布的网站 | 容易出问题 | 大多正常 | 大多正常(吸管、拾取等小范围读取不加噪声) |
| 再次读取同一图像 | 同样的空白值 | 数值不同,噪声立即暴露 | 相同的值(同一页面内) |
| 再次打开页面 | 同样的空白值 | 新的值 | 新的值 |
| 不同网站之间 | 同样的空白值(使用的人少时反而显眼) | 各不相同 | 各不相同 |
※ 对于与预先已知数值的图像进行比对的检测(known-answer),三种方式都会暴露。请参阅下方的“注意事项”。
不仅保护画布(2D 和 OffscreenCanvas),还保护 WebGL、WebGPU、WebCodecs(VideoFrame)、画布录制(captureStream)、文字尺寸(measureText)乃至音频。无论以 8 位还是浮点数读取、读取局部还是全部,也无论经由 getImageData、VideoFrame.copyTo 还是纹理读取,同一像素都会加入相同的噪声,因此靠改变读取方式进行比对,很难去除噪声。新创建的同源 iframe 也会得到同样的保护;在跨源 iframe 中,则由脚本管理器注入该文档的实例用自己的密钥加入噪声(若管理器不向 iframe 注入,则为原始值)。不过,在不透明源 iframe(sandbox、data:)以及 Worker 和音频 Worklet 中,读到的是原始值(1.8 版不包装 Worker 和 Worklet,原因见下方的“1.8 版更新内容”)。
被修改的函数都是包装原函数的 Proxy,因此 toString()、name、length 以及 bind() 的结果都与原函数相同;经由钩子抛出的错误,其堆栈也会去掉本脚本的行,重建成原生函数本应产生的样子。本脚本不会在 window 上留下标记,还会隐藏 Tampermonkey、Violentmonkey 写入堆栈中脚本地址的安装 ID 等用户专属值。不过,在同时禁止 eval 和内联脚本的页面以及 Firefox 上无法隐藏,而且比本脚本先运行的页面代码能够获知这些值和设置(见下方的“已知局限”)。在无需保护的页面上,根本不会挂上钩子。但这并不能让脚本隐身,噪声本身就可能暴露它。
如果某个网站上 Brave Shields 的指纹保护正在生效,本脚本会自动关闭重叠的画布和音频噪声。如果浏览器或其他扩展已经在修改画布(例如 Firefox RFP),本脚本就会让步,关闭自己的画布噪声。这样可以避免因双重修改而导致数值不一致。指纹保护在浏览器于所有地方统一施加时效果最好,因此本脚本是作为辅助手段,为缺少这类保护的 Chromium 内核浏览器而做的。
| 对象 | 网站读取的数值 | 本脚本的处理 | 默认 |
|---|---|---|---|
| 画布 | 绘制图像后读回的像素(toDataURL、toBlob、getImageData、convertToBlob) | 每个页面重新选定的噪声(颜色变化不超过 1 级) | 开启 |
| WebGL、WebGPU | 用 readPixels、copyTextureToBuffer 读取的像素,把画布作为纹理上传后读回的值(约 360×360 以内的画布) | 同样的噪声 | 开启 |
| 视频帧与录制 | VideoFrame.copyTo,由画布生成的 VideoFrame、ImageBitmap 以及 captureStream()(约 360×360 以内的画布) | 同样的噪声 | 开启 |
| 文字尺寸 | 画布 measureText 结果的小数部分 | 移动不超过一格(1/65536 px;值在 256 px 及以上时为 float32 的最小单位) | 开启 |
| 音频 | OfflineAudioContext 的结果、AnalyserNode、DynamicsCompressorNode.reduction、ScriptProcessor 的输入 | 听不见的噪声(每 8 个采样中有 1 个移动 ±1 ulp) | 开启 |
| WebRTC | 页面提供的 STUN、TURN 服务器 | 移除服务器设置(无法隐藏公网 IP) | 关闭 |
不作修改的数值:如果只在窗口中修改,就会与 Worker、请求头、CSS 等本脚本无法触及之处的数值相矛盾,而这种矛盾会成为新的痕迹。因此以下数值保持原样。
| 数值 | 能读到同样数值的地方 |
|---|---|
| CPU 核心数、内存 | 所有 Worker、sandbox iframe,Device-Memory 请求头(网站请求时) |
| GPU 名称、WebGL 和 WebGPU 的上限与功能 | 所有 Worker、sandbox iframe |
| User-Agent、Client Hints、语言 | 所有地方以及请求头 |
| 时区 | 所有地方(修改后屏幕上显示的时间会出错,也会与 IP 所在位置不符) |
| 电池 | 本脚本无法触及的 sandbox iframe |
| 屏幕和窗口尺寸 | CSS 媒体查询 |
| 字体、通过 DOM 测得的文字宽度 | 布局 API,CSS 和 FontFace 的 local() |
💡 在 Chromium 内核浏览器中使用 Tampermonkey 时,需要在浏览器的扩展程序设置中为 Tampermonkey 开启“允许用户脚本”(Allow User Scripts),脚本才能运行。
Violentmonkey 在默认设置下运行用户脚本的时机晚于页面的第一个内联脚本(在 2.49.4 测试版中确认;在 MV2 版的“Synchronous page mode”下,用户脚本会先运行)。因此那个内联脚本读到的是未加噪声的值,还能事先替换内置函数,获知本脚本的管理器地址(名称和安装编号)以及设置(见下方的“已知局限”)。
请不要修改脚本头部的
@grant none、@run-at document-start、@inject-into page。哪怕只申请一项权限(@grant),管理器也会在隔离环境中运行脚本,导致无法修改页面的函数;如果不是document-start,页面就会先读走原始值。
没有单独的设置界面。请在脚本管理器中编辑本脚本,修改顶部的 CONFIG。
| 键 | 默认值 | 说明 |
|---|---|---|
canvas | true | 为画布、WebGL、WebGPU、VideoFrame 的读取以及 measureText 加入噪声 |
audio | true | 为窗口和 iframe 中的音频读取加入噪声(音频 Worklet 的输入保持原始值) |
webrtc | false | 移除页面提供的 STUN、TURN 服务器。无法隐藏公网 IP,开启后视频通话可能无法连接 |
braveMode | 'auto' | 'auto':该网站上 Brave Shields 的指纹保护正在生效时,关闭重叠的功能(canvas、audio);'on':始终关闭;'off':不会仅因浏览器是 Brave 而关闭 |
respectNativeCanvas | true | 如果浏览器或其他扩展已经在修改画布,则关闭画布噪声 |
smallReadsPerSecond | 2048 | 让小范围读取(少于 256 像素且不超过画布的 1/4)可以不加噪声的预算(每秒像素数)。设为 0 则不设例外 |
uploadPixels | 131072 | 为纹理上传、ImageBitmap、new VideoFrame(画布)、录制帧加入噪声的画布尺寸上限(约 360×360)。更大的画布经由这些途径输出时不加噪声 |
sites | {} | 按网站设置的例外(见下文) |
debug | false | 在开发者工具控制台输出 [Shield] 日志(替换了 console.log 的页面代码也会收到这些日志) |
1.7 版的 hardware、webglGpu、hideBrave、battery、workers、noiseScope、siteKeyHours、privateKeyHours 已在 1.8 版中删除。即使它们仍留在你修改过的副本中,也会被忽略。
按网站设置例外:在 sites 中写入域名(包括子域名),并为其指定 false(在该网站关闭)或要覆盖的设置。
sites: {
'photopea.com': { canvas: false }, // 需要原样读取像素值的图像编辑器
'meet.google.com': { webrtc: false }, // 开启 webrtc 时的视频通话网站
'kepler.gl': { smallReadsPerSecond: 8192 }, // 拾取半径较大的地图可视化
'example.com': false, // 在该网站关闭(不挂任何钩子)
},
*.example.com、.example.com、大写字母以及国际化域名(如中文域名)都可以直接照写。canvas、audio、webrtc 全部关闭的页面上,不会挂任何钩子。不过,在 Tampermonkey 和 Violentmonkey 中,堆栈隔离会在读取设置之前进行,因此即使在已通过设置关闭本脚本的网站上,如果页面的 CSP 禁止 eval 或只报告 eval,仍可能产生相应的报告。smallReadsPerSecond、uploadPixels,只关闭 canvas、audio 中的一项,webrtc: true),都可能成为该网站把你和其他用户区分开来的线索。📝 修改设置后,如果脚本自动更新,改过的部分可能会被新版本覆盖,因此请另外记下改过的设置。
new Worker(blob) 就能读到未加噪声的画布值,而且这个值在不同网站上都相同。不透明源 iframe(sandbox、data:)也是如此。{ canvas: false, audio: false } 关闭保护(该网站将看到未受保护的原始指纹)。resistFingerprinting、Brave Shields、Safari 的高级指纹保护。Tor Browser 和 Mullvad Browser 的做法是让所有用户显示相同的指纹,因此请不要在其中添加包括本脚本在内的用户脚本。| 症状 | 解决方法 |
|---|---|
| 在任何网站上都不生效 | 请确认没有修改脚本头部;如果在 Chromium 内核浏览器上使用 Tampermonkey,还要确认已开启“允许用户脚本” |
| 图像编辑器、绘图网站上的颜色有细微变化 | 在 sites 中把该网站设为 { canvas: false } |
| 在画布游戏、地图、3D 查看器中,点击或悬停的对象偶尔不对,或提示框闪烁 | { smallReadsPerSecond: 8192 }(或更大) |
| 频繁把画布作为 WebGL 纹理上传的小画面(标签、HUD)卡顿 | { canvas: false } |
| 银行、支付或登录网站每次都把你识别为新设备 | { canvas: false, audio: false }(该网站将看到原始指纹) |
视频通话无法连接(webrtc: true 时) | { webrtc: false } |
1.7 版中使用的设置(hardware、workers、siteKeyHours 等)不起作用 | 这些设置已在 1.8 版中删除,会被忽略(见下方的“1.8 版更新内容”)。如果你曾为银行、支付网站设置 { siteKeyHours: 0 },请改为 { canvas: false, audio: false } |
| 想确认脚本是否在工作 | 设为 debug: true,在开发者工具控制台中查看 [Shield] 日志 |
crypto.getRandomValues 新生成一个 32 位密钥。密钥不会被存储、写入日志,也不会放在页面能读取的地方;本脚本也不读取 GM_info。globalAlpha = 0.99 就能绕过。{2k, 2k+1} 和整体偏移 1 的 {2k+1, 2k+2} 之间选定,因此即使页面先清除最低位(& 0xFE)再计算哈希,不同页面也不会得到相同的值。measureText 值是以 1/65536 px 为单位的 float32,若随意改动其低位,就会被 Math.fround(w) !== w 识破。因此只在这个网格内移动不超过一格。getChannelData、copyFromChannel 和 ScriptProcessor 的输入对同一采样给出相同的值。createImageBitmap(画布)、new VideoFrame(画布)、captureStream(),以及 createMediaStreamDestination() 前面一条极其微小的变换曲线)也会加入噪声,因此之后无论流向编码器、纹理、<video> 还是 WebRTC,数值都相同。Proxy。数字参数会在原生函数之前,按照与 WebIDL 相同的顺序只转换一次;钩子用到的内置函数在启动时就已保存,因此即使页面之后替换这些函数,也不受影响。userscript-sandbox)通过间接 eval 重新加载脚本主体,并安装这个副本。在 about:blank 以外的文档中,eval 在脚本执行完毕后的 Promise 回调中调用,因此 eval 的 CSP 违规报告中不含本脚本的地址、行号和代码;在禁止 eval 的页面上,则改用由 Trusted Types 策略生成的内联 <script> 加载副本。contentWindow、window.open 等),以及插入节点的函数(appendChild、innerHTML、document.write 等,包括影子根中的插入)返回之后,立即安装同样的钩子;由 HTML 解析器插入的 iframe 会在下一个内联脚本运行之前完成安装,导航到其他文档的 iframe 则会在新文档的第一个脚本运行之前完成安装(剩余的空隙见下方的局限)。uploadPixels(约 360×360)的画布,通过纹理上传、ImageBitmap、new VideoFrame、captureStream 输出时不加噪声。想要更严格,可以调大这个值(偏离默认值后,可能会通过这个边界暴露你的设置)。<img> 或 SVG 图像作为纹理上传并在着色器中读回时,得到的是原始值(为了不破坏地形瓦片、LUT 等数据纹理)。用计算着色器(compute shader)转移后读取 WebGPU 的输出,或从本脚本不处理的格式(如 rgb10a2unorm)读取,得到的也是原始值。getBoundingClientRect、offsetWidth 等)测得的文字宽度和已安装字体列表无法防护。曾经测试过相应的防护,但数值仍会从其他途径泄露,而且会拖慢或破坏网站,因此没有加入。字体需要浏览器层面的保护。webrtc: true 只会移除页面提供的 STUN、TURN 服务器,无法阻止想获知公网 IP 的网站(页面若把自己的服务器作为远端候选地址传入,浏览器就会直接向它发送 UDP 连通性检查)。页面也能察觉到这项设置已开启。要隐藏 IP,请使用浏览器的 WebRTC IP 处理策略,或关闭 WebRTC。'self' 和主机名的常见 script-src)以及 Firefox 上无法进行隔离,管理器地址中的用户专属值(Tampermonkey 的安装 ID 等)可能经由部分途径暴露。在 CSP 禁止或仅报告 eval 的页面上,每个文档(每条限制 eval 的策略)会产生一份 eval 的违规报告(about:blank 以外文档的报告中不含本脚本的地址、行号和代码)。在 eval 被禁止、改用内联 <script> 加载副本的页面上,每条禁止或仅报告这种内联脚本的策略还会再产生一份含有 chrome-extension 和本脚本固定行号的报告(1.7 版没有这种报告)。about:blank 窗口)可以事先替换内置函数,从而取得本脚本从堆栈中读取的管理器地址中的用户专属值(Tampermonkey 的安装 ID、Violentmonkey 的名称和安装编号,在所有网站上都相同)以及设置(包括 sites 中的域名),还能决定或获知该窗口的噪声密钥(仅限那一次页面加载的密钥)。这类代码先行开启的性能分析器,也可能在安装前的样本中看到管理器地址。本版本没有修复这一点(1.7 版也是如此)。Script error. 传给页面,页面自身的错误收集会因此丢失这些信息(这是 1.8 版的变化;1.7 版会传出消息和错误对象,位置显示为 userscript-sandbox)。javascript: 地址的文档;HTML 中写入的封闭声明式影子根里的 iframe 则无法保护。new VideoFrame(画布) 会多花几毫秒。1.8 版重新审视了 1.7 版,修复了安全问题,并减少了脚本自身留下的痕迹。在此过程中,部分功能被有意删除;已删除的设置即使仍留在你修改过的副本中,也会被忽略。
noiseScope、siteKeyHours、privateKeyHours)。1.7 版用安装 ID 和修改时间生成按网站划分的密钥,因此一旦比本脚本先运行的代码,或事先对新窗口(初始 about:blank)动过手脚的页面取得了这些材料,就能算出该用户在所有网站上的密钥。现在本脚本不再读取 GM_info,也不存储密钥,因此这类代码能决定或获知的只有那一次页面加载的密钥(不过仍能取得管理器地址和设置,见已知局限中的“先运行的代码”)。作为代价,会记住设备的网站可能每次访问都把你当作新设备(如果在 1.7 版中为银行、支付网站设置了 { siteKeyHours: 0 },请改为 { canvas: false, audio: false })。hardware、webglGpu、hideBrave、battery)。CPU 核心数和内存、GPU 名称、Brave 痕迹、电池都只能在窗口中修改,因此与同一页面的 sandbox iframe、Worker 和请求头中可见的真实数值相矛盾,而这种矛盾暴露了伪装。现在这一痕迹已经消失,但只读取窗口的采集器也会看到真实数值。workers)。这项设置(默认关闭)开启时曾存在两个安全问题:重定向到其他源的 Worker 地址中的脚本可能会以本网站的源运行;在某些 CSP 下,页面能读到本网站的噪声密钥和全部设置。现在 Worker 始终读取原始值,这类重定向也会像原生行为一样失败。blob: 地址,进而读到本网站的噪声密钥和全部设置(包括 sites 中的域名)。audio 仍会为窗口和 iframe 中的音频读取加入噪声。toBlob 回调不触发的问题(两者在 1.7 版中也存在)。此前,页面用另一个窗口的函数导出或读取画布时,Chrome 141 中的标签页可能会崩溃(在本脚本未能先行到达的同源窗口中,现在仍可能如此);而在初始空白窗口被新文档重新使用的同源 iframe 和弹出窗口中,toBlob 的回调曾无法触发。about:blank 窗口除外);在禁止 eval 但允许内联脚本的页面上也会进行隔离(在连内联脚本也禁止的页面上,仍像以前一样运行原始脚本,并会多产生一份含有 chrome-extension 和固定行号的报告)。在 eval 或内联脚本可用的页面上,安装过程中堆栈和性能分析器样本里出现管理器地址的问题也已消除(原始脚本在安装前运行期间的样本中仍会出现)。作为代价,安装会推迟到脚本执行之后(见已知局限中的“安装时机”)。toString 识破的痕迹(开启画布噪声时,这项修复仅在 Chromium 内核浏览器上有效;重新导航的 iframe、以同源地址打开的弹出窗口等情况仍会留下这一痕迹);以及打开同源弹出窗口时,发往页面报告服务器的 COOP 违规报告。Array.prototype 上的索引 getter;改为像原生代码一样读取传给 WebGPU 的字典;用 Range 插入影子根的 iframe 也会在插入时立即安装钩子。在无需保护的页面上不挂任何钩子和监听器;debug 日志即使失败,也不会跳过后续的安装。respectNativeCanvas 也会对每个窗口重新检查,堵住了以同源地址打开的弹出窗口中部分窗口(如 <embed> 窗口)读到原始画布的空隙。如果发现出现异常的网站或新的绕过方法,请在反馈标签页留下网站地址或复现代码。我会逐一复现、判定并修复。
本脚本适用以下许可协议。中文译文旨在帮助理解,仅供参考;如与英文原文有出入,以英文原文为准。
Copyright (c) 2026 LiteWeaver. All Rights Reserved.
1. PERMITTED USE
You are permitted to use this script for personal, non-commercial purposes only. You may also change the settings in the CONFIG section of this script for your own personal use.
2. RESTRICTIONS
You may not reproduce, distribute, modify, create derivative works of, publicly display, or commercially exploit this software, in whole or in part, without explicit written permission from the copyright holder.
3. DISCLAIMER OF WARRANTY AND LIABILITY
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
版权所有 (c) 2026 LiteWeaver。保留所有权利。
1. 允许的使用
您仅可将本脚本用于个人非商业用途。您也可以出于个人自用目的,更改本脚本 CONFIG 部分中的设置。
2. 限制
未经版权持有人明确的书面许可,您不得复制、分发、修改、公开展示或以商业方式利用本软件的全部或部分,也不得基于本软件的全部或部分创作衍生作品。
3. 担保与责任的免除
本软件由版权持有人“按原样”提供,版权持有人不作任何明示或暗示的担保,包括但不限于对适销性和特定用途适用性的暗示担保。在任何情况下,对于因使用本软件而以任何方式产生的任何直接、间接、附带、特殊、惩戒性或后果性损害(包括但不限于采购替代商品或服务;使用、数据或利润损失;或业务中断),无论其因何引起,也无论基于何种责任理论,不论是合同责任、严格责任还是侵权责任(包括过失或其他情形),即使已被告知发生此类损害的可能性,版权持有人均不承担责任。
هەڵسەنگاندن: 0