動態

詳情 返回 返回

記錄---瀏覽器指紋-探究前端如何識別用户設備 - 動態 詳情

🧑‍💻 寫在開頭

點贊 + 收藏 === 學會🤣🤣🤣

什麼是瀏覽器指紋?

瀏覽器指紋,是用來唯一標識你瀏覽器的一組“特徵值”。它不是我們理解中的那種真實指紋,而是通過收集瀏覽器、操作系統、設備分辨率、字體、插件等信息,組合成的一個獨特 ID。

和傳統的 Cookie 不同,瀏覽器指紋不需要在用户設備上存儲任何東西,完全是“讀取現有信息”來識別用户。

使用背景

在最近的項目中,有個小需求:想用用户的設備作為唯一憑證,來驗證身份

一開始我想着簡單粗暴點,用 JS 獲取手機的 IMEI 或 PC 的序列號。但查了下資料後才發現,這根本行不通——JS 根本沒權限訪問這些底層硬件信息,安全機制早就把這條路堵死了。

後來才反應過來,我真正想要的,是一個“設備唯一標識”,也就是——瀏覽器指紋。

可行方案

查閲了一些資料之後,目前比較常見的幾種瀏覽器指紋方案如下:

  • Navigator 指紋:瀏覽器類型、版本、系統平台等信息。
  • Canvas 指紋:讓瀏覽器繪製一段隱藏的圖像,然後讀取圖像的像素差異,不同設備會有微小區別。
  • WebGL 指紋:利用顯卡和圖形驅動渲染差異,獲取設備的唯一特徵。
  • 字體、插件、時區、屏幕分辨率等:這些信息組合起來也能提供一定的識別度。

當然,單一方案識別率可能不高,但多種信息結合後,指紋的唯一性就會明顯提升。

Navigator 指紋

Navigator 是前端獲取瀏覽器和部分設備環境信息的重要接口。

下面是一些常用的屬性和方法(跨瀏覽器兼容性較好的為主):

企業微信截圖_20250807180856

企業微信截圖_20250807180907

 偷個懶,讓Tare直接幫我寫個Navigator 指紋示例吧。

企業微信截圖_20250807180918

 

<!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>

代碼生成完畢,點擊應用直接預覽:

企業微信截圖_20250807180931

經過測試,在同一個電腦上,這個指紋是穩定的,多次執行,這個值不會變。

但這這個指紋明顯有缺陷,我係統語言或者瀏覽器升級後,這個指紋肯定會改變。

Canvas 指紋

由於不同設備(包括操作系統、顯卡、驅動、字體渲染引擎等)在繪製同一段 Canvas 內容時會存在細微差異,最終得到的圖像數據(通常是像素或轉成 base64)在不同設備上往往是不同的。

這些細微差異生成的哈希值就是“指紋”,由於只與設備性能有關,指紋穩定性顯然比Navigator 指紋高一些。

企業微信截圖_20250807180941

 

<!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>
生成的指紋還是很不錯的。

企業微信截圖_20250807180952

 其他幾種方式生成瀏覽器指紋都大同小異,這裏就不介紹了。

 

本文轉載於:https://juejin.cn/post/7511915154032853018

如果對您有所幫助,歡迎您點個關注,我會定時更新技術文檔,大家一起討論學習,一起進步。

user avatar ddup365 頭像 jingzhexiaoyu 頭像 compose_hub 頭像 yils_lin 頭像 hole 頭像 chenchaoyang666 頭像 kkocdko 頭像
點贊 7 用戶, 點贊了這篇動態!
點贊

Add a new 評論

Some HTML is okay.