稀土掘金技术社区 06月19日 09:47
浏览器指纹-探究前端如何识别用户设备
index_new5.html
../../../zaker_core/zaker_tpl_static/wap/tpl_guoji1.html

 

本文探讨了浏览器指纹技术,这是一种用于唯一标识用户设备的方法。文章首先介绍了浏览器指纹的概念和应用背景,然后详细阐述了Navigator指纹和Canvas指纹的实现原理和代码示例。通过收集浏览器、操作系统、设备等信息,浏览器指纹能够在不使用Cookie的情况下识别用户。文章还提供了代码示例,帮助读者理解如何获取和生成浏览器指纹,为前端开发提供了有价值的参考。

🔍 **浏览器指纹的概念与应用:** 浏览器指纹通过收集浏览器、操作系统、设备分辨率、字体、插件等信息,生成一个独特的ID,用于唯一标识用户设备,实现设备身份验证。

🧭 **Navigator 指纹的实现:** Navigator指纹利用Navigator接口提供的属性,如userAgent、platform、language等,收集浏览器和设备信息,通过SHA-256哈希算法生成指纹,但该指纹容易受浏览器升级等因素影响。

🎨 **Canvas 指纹的实现:** Canvas指纹通过绘制隐藏的图像,读取图像的像素差异,利用不同设备在图形渲染上的微小差异生成指纹。由于与设备性能相关,Canvas指纹的稳定性高于Navigator指纹。

原创 石小石Orz 2025-06-19 08:31 重庆

点击关注公众号,“技术干货”及时达!

(金石瓜分12天倒计时,速戳上图了解详情)

大家好,我是

石小石

,一个热爱技术分享的开源社区贡献者。写有《油猴脚本实战指南[1]》、《Vite 极速入门与进阶[2]》、《Threejs 极速入门》、《鸿蒙基础开发实践[3]》、《前端学 Java》等专栏。目前专注于微前端架构与 AI 相关技术的研究与工程实践。
什么是浏览器指纹?浏览器指纹,是用来唯一标识你浏览器的一组 “特征值”。它不是我们理解中的那种真实指纹,而是通过收集浏览器、操作系统、设备分辨率、字体、插件等信息,组合成的一个独特 ID。

和传统的 Cookie 不同,浏览器指纹不需要在用户设备上存储任何东西,完全是 “读取现有信息” 来识别用户。

使用背景在最近的项目中,有个小需求:「想用用户的设备作为唯一凭证,来验证身份」

一开始我想着简单粗暴点,用 JS 获取手机的 IMEI 或 PC 的序列号。但查了下资料后才发现,这根本行不通——JS 根本没权限访问这些底层硬件信息,安全机制早就把这条路堵死了。

后来才反应过来,我真正想要的,是一个 “设备唯一标识”,也就是——浏览器指纹。

可行方案查阅了一些资料之后,目前比较常见的几种浏览器指纹方案如下:

「Navigator 指纹」:浏览器类型、版本、系统平台等信息。

「Canvas 指纹」:让浏览器绘制一段隐藏的图像,然后读取图像的像素差异,不同设备会有微小区别。

「WebGL 指纹」:利用显卡和图形驱动渲染差异,获取设备的唯一特征。

「字体、插件、时区、屏幕分辨率等」:这些信息组合起来也能提供一定的识别度。

当然,单一方案识别率可能不高,但多种信息结合后,指纹的唯一性就会明显提升。

Navigator 指纹「Navigator 是前端获取浏览器和部分设备环境信息的重要接口。」

下面是一些常用的属性和方法(跨浏览器兼容性较好的为主):

属性 / 方法

作用说明

示例代码

navigator.userAgent

获取浏览器的用户代理字符串,可以用于判断浏览器类型、系统类型

navigator.userAgent

navigator.platform

获取运行环境的操作系统平台类型(如 Win32、Linux x86_64、MacIntel)

navigator.platform

navigator.appVersion

获取浏览器版本信息和部分平台信息

navigator.appVersion

navigator.appName

获取浏览器名称(大多数现代浏览器返回 “Netscape”)

navigator.appName

navigator.language

返回当前浏览器的首选语言(如 “zh-CN”、“en-US”)

navigator.language

navigator.languages

返回用户的首选语言列表

navigator.languages

navigator.hardwareConcurrency

返回可用的逻辑处理器数量(CPU 核心数)

navigator.hardwareConcurrency

navigator.plugins

返回当前安装的插件列表(仅桌面浏览器有意义,且有兼容性限制)

navigator.plugins

navigator.onLine

判断当前浏览器是否联网

navigator.onLine

navigator.cookieEnabled

判断浏览器是否启用 Cookie

navigator.cookieEnabled

navigator.geolocation

提供地理位置定位服务(需要用户授权)

navigator.geolocation.getCurrentPosition(...)

navigator.maxTouchPoints

支持的最大触控点个数(触屏设备可用)

navigator.maxTouchPoints

navigator.mediaDevices

访问音视频设备管理 API(如获取麦克风、摄像头)

navigator.mediaDevices.getUserMedia(...)

navigator.clipboard

读写系统剪贴板(部分浏览器需要 https 环境和权限)

navigator.clipboard.writeText("Hello")

navigator.connection

获取网络连接信息对象(如带宽、类型,部分浏览器支持)

navigator.connection.effectiveType

navigator.userAgentData

在新标准中可用的一种用户代理信息对象,部分浏览器已支持,用户隐私性更高

navigator.userAgentData

偷个懒,让 「Tare」 直接帮我写个 Navigator 指纹示例吧。

<!DOCTYPE html><html><head>    <title>Navigator 指纹示例</title></head><body>    <h2>Navigator 指纹示例</h2>    <pre id="output"></pre>    <script>        async function getNavigatorFingerprint() {            // 收集 navigator 相关信息            const data = {                userAgent: navigator.userAgent,                platform: navigator.platform,                language: navigator.language,                languages: navigator.languages,                cookieEnabled: navigator.cookieEnabled,                hardwareConcurrency: navigator.hardwareConcurrency || 'N/A',                deviceMemory: navigator.deviceMemory || 'N/A',                webdriver: navigator.webdriver || false,            };            // 将数据转成字符串            const dataString = JSON.stringify(data);            // 计算 SHA-256 哈希            const hashBuffer = await crypto.subtle.digest(                "SHA-256",                new TextEncoder().encode(dataString)            );            // 转成十六进制字符串            const hashArray = Array.from(new Uint8Array(hashBuffer));            const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');            return { data, fingerprint: hashHex };        }        getNavigatorFingerprint().then(result => {            const output = document.getElementById('output');            output.textContent =                "采集到的 Navigator 信息:\n" + JSON.stringify(result.data, null, 2) +                "\n\n生成的指纹(SHA-256):\n" + result.fingerprint;        });    </script></body></html>

代码生成完毕,点击应用直接预览:

经过测试,在同一个电脑上,这个指纹是稳定的,多次执行,这个值不会变。

但这这个指纹明显有缺陷,我系统语言或者浏览器升级后,这个指纹肯定会改变。

Canvas 指纹由于不同设备(包括操作系统、显卡、驱动、字体渲染引擎等)在绘制同一段 Canvas 内容时会存在细微差异,最终得到的图像数据(通常是像素或转成 base64)在不同设备上往往是不同的。

这些细微差异生成的哈希值就是 “指纹”,由于只与设备性能有关,指纹稳定性显然比 Navigator 指纹高一些。

<!DOCTYPE html><html><head>    <title>简单Canvas指纹示例</title></head><body>    <h2>简单Canvas指纹示例</h2>    <p>请打开控制台(F12)查看结果</p>    <script>        // 创建一个简单的Canvas指纹生成函数        function generateCanvasFingerprint() {            // 创建canvas元素            const canvas = document.createElement('canvas');            canvas.width = 200;            canvas.height = 100;            // 获取绘图上下文            const ctx = canvas.getContext('2d');            // 填充背景            ctx.fillStyle = 'white';            ctx.fillRect(0, 0, canvas.width, canvas.height);            // 绘制一些图形和文字            // 绘制红色矩形            ctx.fillStyle = 'red';            ctx.fillRect(20, 20, 50, 50);            // 绘制蓝色圆形            ctx.fillStyle = 'blue';            ctx.beginPath();            ctx.arc(120, 45, 25, 0, Math.PI * 2);            ctx.fill();            // 绘制文本            ctx.fillStyle = 'black';            ctx.font = '16px Arial';            ctx.fillText('Canvas指纹', 60, 80);            // 获取canvas数据URL            const dataURL = canvas.toDataURL();            // 简单哈希函数            function simpleHash(str) {                let hash = 0;                for (let i = 0; i < str.length; i++) {                    const char = str.charCodeAt(i);                    hash = ((hash << 5) - hash) + char;                    hash = hash & hash; // 转换为32位整数                }                return hash.toString(16); // 转换为16进制            }            // 计算指纹            const fingerprint = simpleHash(dataURL);            return {                fingerprint: fingerprint,                dataURL: dataURL            };        }        // 生成并输出指纹        const result = generateCanvasFingerprint();        console.log('Canvas指纹:', result.fingerprint);        console.log('Canvas数据URL前100个字符:', result.dataURL.substring(0, 100) + '...');        // 如果浏览器支持更安全的哈希算法,也可以使用它        if (window.crypto && window.crypto.subtle) {            const encoder = new TextEncoder();            const data = encoder.encode(result.dataURL);            window.crypto.subtle.digest('SHA-256', data)                .then(hashBuffer => {                    // 将哈希缓冲区转换为十六进制字符串                    const hashArray = Array.from(new Uint8Array(hashBuffer));                    const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');                    console.log('Canvas指纹(SHA-256):', hashHex);                });        }    </script></body></html>

生成的指纹还是很不错的。

其他几种方式生成浏览器指纹都大同小异,这里就不介绍了。

AI编程资讯AI Coding专区指南:https://aicoding.juejin.cn/aicoding

""~

阅读原文

跳转微信打开

Fish AI Reader

Fish AI Reader

AI辅助创作,多种专业模板,深度分析,高质量内容生成。从观点提取到深度思考,FishAI为您提供全方位的创作支持。新版本引入自定义参数,让您的创作更加个性化和精准。

FishAI

FishAI

鱼阅,AI 时代的下一个智能信息助手,助你摆脱信息焦虑

联系邮箱 441953276@qq.com

相关标签

浏览器指纹 前端技术 设备识别 Navigator Canvas
相关文章