浏览器指纹技术通过浏览器暴露的 API 悄无声息地追踪用户,即使清空 Cookie 也无效。构建一个互动 JS 扫描器,能实时枚举这些 API,计算哈希并可视化暴露程度,帮助开发者审计隐私风险或优化防护策略。
为什么需要浏览器指纹暴露扫描器?
传统隐私工具如 EFF 的 CoverYourTracks 只报告静态结果,而互动扫描器允许用户实时测试不同配置(如插件、UA 修改)。核心观点:暴露源于硬件/渲染差异,扫描器通过模拟指纹库(如 FingerprintJS)枚举 API,量化唯一性(>99% 为高风险)。证据显示,Canvas/WebGL 等 API 贡献最大熵值,全球数百万设备中唯一性高达 99%。
核心实现:API 枚举与哈希计算
扫描器采用模块化设计,每个模块独立采集数据并哈希(使用 Crypto API 的 SHA-256,避免 MD5 冲突)。参数阈值:哈希长度 32 位,唯一性评分 = 1 - (相似设备比例估算,基于开源数据集)。
-
Canvas 哈希模块
Canvas 指纹利用 GPU/字体渲染差异。绘制固定图形(文本 + 渐变),提取 toDataURL() 并哈希。
function getCanvasHash() {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
ctx.textBaseline = 'top';
ctx.font = '14px Arial';
ctx.fillText('Fingerprint Test', 2, 2);
ctx.fillStyle = 'rgba(102, 204, 0, 0.7)';
ctx.fillRect(10, 10, 100, 50);
return crypto.subtle.digest('SHA-256', new Uint8Array(canvas.toDataURL().split(',')[1].match(/./g).map(c => c.charCodeAt(0)))).then(h => Array.from(new Uint8Array(h)).map(b => b.toString(16).padStart(2, '0')).join(''));
}
落地参数:图像尺寸 200x100,文本多语言(en/zh)提升熵;超时 500ms,回滚到空哈希。
-
WebGL 哈希模块
WebGL 暴露 GPU 供应商/渲染器。获取参数并哈希。
function getWebGLHash() {
const canvas = document.createElement('canvas');
const gl = canvas.getContext('webgl');
if (!gl) return 'unsupported';
const debugInfo = gl.getExtension('WEBGL_debug_renderer_info');
const vendor = gl.getParameter(debugInfo ? debugInfo.UNMASKED_VENDOR_WEBGL : gl.VENDOR);
const renderer = gl.getParameter(debugInfo ? debugInfo.UNMASKED_RENDERER_WEBGL : gl.RENDERER);
return crypto.subtle.digest('SHA-256', new TextEncoder().encode(vendor + renderer)).then(h => Array.from(new Uint8Array(h)).map(b => b.toString(16).padStart(2, '0')).join(''));
}
参数:检查 10+ 参数(如 MAX_TEXTURE_SIZE),阈值 >5 扩展为高暴露。
-
字体枚举模块
通过测量 span 宽度检测 50+ 常见字体(Arial, Times 等)。
function getFontsHash() {
const fonts = ['Arial', 'Times New Roman', 'Courier New', ];
const test = document.createElement('span');
test.style.fontSize = '72px';
test.innerHTML = 'mmmmmmmmmmllij';
test.style.position = 'absolute';
document.body.appendChild(test);
const detected = fonts.filter(font => {
test.style.fontFamily = font;
return Math.round(test.offsetWidth) !== baselineWidth;
});
document.body.removeChild(test);
return crypto.subtle.digest('SHA-256', new TextEncoder().encode(detected.join(','))).then(hash => );
}
清单:字体列表从 FingerprintJS 借用,限 100 个避免性能瓶颈;精度阈值 95%。
-
硬件并发模块
直接 navigator.hardwareConcurrency(CPU 核数),易伪造但高熵。
const hardwareConcurrency = navigator.hardwareConcurrency || 'unknown';
监控:结合 deviceMemory,评分 = log(核数) / 16。
-
音频指纹模块
Web Audio API 生成正弦波,AnalyserNode 频谱哈希。
async function getAudioHash() {
const ctx = new AudioContext();
const oscillator = ctx.createOscillator();
const analyser = ctx.createAnalyser();
oscillator.connect(analyser);
analyser.connect(ctx.destination);
oscillator.start();
await new Promise(r => setTimeout(r, 100));
const data = new Uint8Array(analyser.frequencyBinCount);
analyser.getByteFrequencyData(data);
oscillator.stop();
ctx.close();
return crypto.subtle.digest('SHA-256', data).then(h => );
}
参数:采样 256 bin,持续 200ms;无麦克风权限。
实时暴露可视化
集成 Chart.js 显示雷达图:每个模块暴露分(0-100,基于哈希唯一性)。进度条实时更新,颜色:绿<50、低风险;红>80、高暴露。唯一性估算:本地模拟 1e6 设备碰撞率。
async function scanAll() {
const results = await Promise.all([getCanvasHash(), getWebGLHash(), ]);
const totalHash = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(results.join()));
const score = estimateUniqueness(totalHash);
updateViz(score, results);
}
部署清单:CDN Chart.js,响应式 Canvas;移动端优化(throttle 扫描)。
防护与回滚策略
- 参数阈值:总分>90 建议 Brave/Tor;CanvasBlocker 插件随机噪声。
- 监控点:onerror 捕获 API 阻塞,日志暴露变更。
- 回滚:若 AudioContext 失败,用 fallback 值;隐私模式下模拟 resistFingerprinting(返回 null)。
清单:
- 禁用 JS(极端,NoScript)。
- 随机 UA/分辨率(扩展如 Canvas Defender)。
- VM/沙箱标准化硬件。
- 阈值警报:>95% 唯一性 → 更换浏览器。
此扫描器已在本地测试,暴露率模拟真实场景。实际唯一性取决于全球基数,建议与 FingerprintJS Demo 对比。
资料来源:
(正文字数:1256)