WebGL 不僅用於炫酷的網頁特效,還能透過 GPU 渲染差異精準追蹤用戶。深入了解 WebGL 指紋如何提取顯示卡與驅動資訊,以及有哪些有效的防範手段。
WebGL 指紋透過查詢你的顯示卡硬體、並觀察它算繪 3D 場景的具體方式來辨識裝置。由於顯示卡型號、驅動程式版本與作業系統的每一種組合都會產生略有差異的輸出、並回報略有不同的能力參數,網站無需任何授權、Cookie 或本機儲存,就能讀取你的 GPU 廠商與算繪器字串、列舉支援的擴充功能與數值上限,並把算繪出的影像雜湊成一個穩定的識別碼。這使得 WebGL 成為現代瀏覽器指紋中資訊熵最高的訊號之一。
WebGL 是什麼,為何會暴露硬體身份
WebGL 是一套 JavaScript API,讓網頁能夠低階地存取 GPU,實現硬體加速的二維與三維圖形算繪。它本質上是瀏覽器對 OpenGL ES 的繫結,這意味著當你呼叫 WebGL 時,請求會穿過瀏覽器、穿過圖形驅動程式,一路抵達機器內部那塊實體顯示卡。
正是這種深層存取讓它成為指紋蒐集的富礦。為了高效繪圖,WebGL 必須暴露硬體的能力——支援多大的材質、有哪些可選特性、著色器如何對浮點數取整。同時它產生的輸出也因硬體而異:同一段繪製指令,在 NVIDIA 顯示卡、Apple GPU 與 Intel 內顯上會得到略有差別的像素,因為它們對點陣化、反鋸齒與浮點運算的實作各不相同。
WebGL 訊號大致分為兩類:宣告型中介資料(顯示卡自我回報的字串與數值)以及算繪輸出(實際繪製場景時產生的像素)。兩者共同補充了 Canvas 指紋偵測所探測的二維算繪路徑,也一起匯入我們在瀏覽器指紋完整指南中描述的整體圖像。
高資訊量的資料點
顯示卡廠商與算繪器字串
WebGL 中辨識度最高的單項訊號,是未遮罩的廠商與算繪器字串。預設情況下標準的 VENDOR 與 RENDERER 參數只回傳通用值,但 WEBGL_debug_renderer_info 擴充功能會暴露真實的硬體身份——例如 Google Inc. (NVIDIA) 以及 ANGLE (NVIDIA, NVIDIA GeForce RTX 3070 Direct3D11 vs_5_0 ps_5_0, D3D11) 這樣的字串。
這條字串往往會透露你的 GPU 型號、算繪後端(Direct3D、Metal、或經由 ANGLE 的 OpenGL),有時還包括驅動程式資訊。僅憑它就能把你縮小到一小撮使用者之中,因為精確的「GPU+後端」組合遠比人們想像的更稀有。
這條字串現在是否真的可讀,很大程度上取決於瀏覽器。在預設的 Chrome 或 Edge 中依然可讀;Brave 與 Firefox 則越來越不然——具體的逐瀏覽器現況見下文「瀏覽器現在隱藏了什麼」。
支援的擴充功能清單
WebGL 自帶一組核心特性,外加數十個可選擴充功能。getSupportedExtensions() 回傳的清單——以及它的排列順序——取決於顯示卡、驅動程式與瀏覽器版本。兩台顯示卡型號相同的裝置,若驅動程式或瀏覽器組建不同,這裡仍可能出現差異,從而再增加一層區分度。這也讓它成為基於雜湊的指紋採集的常用手法:指令碼不需要解析這份清單,只需對它取雜湊——一個穩定的雜湊值和字串本身一樣好用,而這正是 Brave 現在著手攻擊的特性(見下文「瀏覽器現在隱藏了什麼」)。
數值參數與著色器精度
WebGL 暴露了一長串反映硬體能力的數值上限:MAX_TEXTURE_SIZE、MAX_VIEWPORT_DIMS、MAX_RENDERBUFFER_SIZE、鋸齒線寬與點尺寸範圍,以及頂點和片段著色器可用的最大 uniform 向量數。著色器精度——透過 getShaderPrecisionFormat() 查詢高/中/低精度的浮點與整數格式——進一步增加了細緻度,因為精度行為與晶片本身緊密相關。
以算繪為基礎的雜湊
最強大的技術與 Canvas 指紋如出一轍,只是改由 GPU 驅動。指令碼會算繪一個刻意設計得很「刁鑽」的場景——漸層、光照、透明度、曲面幾何——用 readPixels() 把像素讀回並做雜湊。不同 GPU 與驅動程式在浮點取整、反鋸齒與材質過濾上的差異,會產生一個在硬體家族之間各不相同、但對同一裝置保持穩定的雜湊。由於它捕捉的是行為而非僅僅是宣告值,要令人信服地偽造它要難得多。
程式碼層面的實際觀察
下面的程式碼片段蒐集了指紋指令碼會採集的核心 WebGL 訊號。你可以透過 BrowserInsight 的指紋偵測工具查看自己瀏覽器的等效即時結果。
function getWebGLFingerprint() {
const canvas = document.createElement('canvas');
const gl =
canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
if (!gl) return { supported: false };
// 1. 透過 debug 擴充功能讀取未遮罩的 GPU 廠商與算繪器
const debugInfo = gl.getExtension('WEBGL_debug_renderer_info');
const vendor = debugInfo
? gl.getParameter(debugInfo.UNMASKED_VENDOR_WEBGL)
: gl.getParameter(gl.VENDOR);
const renderer = debugInfo
? gl.getParameter(debugInfo.UNMASKED_RENDERER_WEBGL)
: gl.getParameter(gl.RENDERER);
// 2. 數值能力上限
const params = {
maxTextureSize: gl.getParameter(gl.MAX_TEXTURE_SIZE),
maxViewportDims: gl.getParameter(gl.MAX_VIEWPORT_DIMS),
maxRenderbufferSize: gl.getParameter(gl.MAX_RENDERBUFFER_SIZE),
aliasedLineWidth: gl.getParameter(gl.ALIASED_LINE_WIDTH_RANGE),
};
// 3. 片段高精度浮點格式的著色器精度
const precision = gl.getShaderPrecisionFormat(
gl.FRAGMENT_SHADER,
gl.HIGH_FLOAT
);
// 4. 支援的擴充功能清單(存在與否、順序都有資訊量)
const extensions = gl.getSupportedExtensions();
return {
supported: true,
vendor,
renderer,
params,
precision: { rangeMin: precision.rangeMin, prec: precision.precision },
extensions,
};
}
以算繪為基礎的雜湊則更進一步:它編譯一個著色器,繪製一個帶光照的漸層圖形,呼叫 gl.readPixels() 把結果讀入一個型別化陣列,再把該陣列送入雜湊函式。得到的值對你的裝置保持恆定,卻在不同硬體之間各不相同。
WebGL 增加了多少資訊熵
資訊熵衡量一個訊號能把「你是誰」縮小到何種程度。WebGL 對追蹤者格外有價值,恰恰因為它攜帶的資訊熵很高且十分穩定:你的顯示卡不會在兩次頁面載入之間改變,大多數使用者也從不更新驅動程式。廠商/算繪器字串、擴充功能清單、數值上限與算繪雜湊之間存在部分相關——它們都源自同一塊硬體——但每一項都捕捉到了別項遺漏的細節。
實際上 WebGL 極少單獨使用。它會與 Canvas、音訊、字型、螢幕尺寸以及數十種其他屬性組合在一起。下表對比了主要的 WebGL 訊號類型,以及各自被偽造的難易程度。
| WebGL 訊號 | 暴露的內容 | 穩定性 | 偽造難度 |
|---|---|---|---|
| 廠商/算繪器字串 | GPU 型號+算繪後端 | Chrome/Edge 中極高;Brave 1.93+ 中為通用值,不具辨識度 | 易於覆寫,但會破壞一致性 |
| 支援的擴充功能清單 | 驅動程式+瀏覽器特性集 | 高;Brave 1.93+ 中依站點隨機化 | 中等——清單須保持自洽 |
| 數值參數 | 硬體能力上限 | 極高 | 中等——各值相互關聯 |
| 著色器精度 | 浮點運算行為 | 高 | 難——與真實晶片繫結 |
| 算繪像素雜湊 | 真實的 GPU 算繪行為 | 高 | 極難——須偽造真實輸出 |
由於中介資料必須與算繪輸出彼此吻合,粗糙的偽造往往反而增加唯一性:一台回報 Intel 算繪器字串、卻產出 NVIDIA 風格像素的裝置,比一台老老實實如實上報的裝置更顯眼。
瀏覽器現在隱藏了什麼
以上訊號描述的是預設的 Web 平台行為。各家瀏覽器正越來越多地偏離這一預設狀態,截至 2026 年 8 月,「WebGL 理論上能讀到什麼」與「某個訪客的瀏覽器實際回傳什麼」之間的落差,已經比以往任何時候都更大。最近、也最具體的例子是 Brave 的隱私更新 #38,它隨 Brave 1.93 預設開啟,涵蓋 Brave 列出的兩個平台:桌面端與 Android 端。Brave 說明這是歷時數日的漸進式推送,因此並非所有使用者都會立刻看到。它改變了前文提到的三項訊號:
- 廠商與算繪器字串被去識別化。 Brave 不再透過
WEBGL_debug_renderer_info回傳你真實的 GPU 型號,而是把UNMASKED_VENDOR_WEBGL/UNMASKED_RENDERER_WEBGL換成一個所有 Brave 使用者共用的通用字串。前文的描述在 Chrome 與 Edge 的預設設定下依然成立——但已不再適用於 Brave。 - WebGPU 適配器描述資訊被清空。
GPUAdapterInfo——WebGL 廠商/算繪器字串在 WebGPU 中的對應物,把vendor、architecture、device作為一等屬性直接揭露、無需任何偵錯擴充功能——被 Brave 清空,而不是任由同樣的硬體身份透過這個較新的 API 洩露。我們在《WebGPU 指紋:WebGL 之後的下一代 GPU 身份識別》中深入介紹了這個採集面;這裡的簡短結論是:Brave 1.93 用它關閉 WebGL 廠商字串的同一種方式,也關閉了這個缺口。 - 擴充功能清單被隨機化,而不只是被隱藏。Brave 會為
getSupportedExtensions()注入隨機性,讓基於雜湊的指紋指令碼在每個瀏覽工作階段、每個站點(eTLD+1)、每個儲存區之間都看到不同的值。這直接擊潰了前文描述的雜湊採集手法:唯有當同一份輸入在你造訪的每個網站上都產出相同雜湊時,雜湊才能充當有效的識別碼。一旦底層的擴充功能清單本身就隨站點而變,雜湊也會隨之改變——追蹤者在 A 站點採集到的值,就不再與 B 站點採集到的值相符,即使你的硬體從未改變,它也徹底失去了作為跨站識別碼的作用。
歸屬很重要,因為這些防護並非普遍適用。Brave 在 1.93 及以後版本預設執行去識別化與隨機化。Firefox 走的是另一條路:開啟 privacy.resistFingerprinting 後,它會直接停用 WEBGL_debug_renderer_info,因此該模式下每個 Firefox 使用者拿到的都是同一個通用的 VENDOR/RENDERER 值,而非隨機化的值。Chrome 與 Edge 預設既不去識別化也不隨機化——未遮罩的字串與真實的擴充功能清單仍如前文所述那樣可讀。這並不代表任何瀏覽器已經「解決」了指紋追蹤問題,Brave 自己的發佈說明也明確表示這仍是分階段觸及使用者的過程——請把這一節視為「某一家廠商目前的防護現況」,而非「整個 Web 的現況」。
這樣一條高辨識度的字串,當初為何能在沒有任何授權彈窗的情況下被讀取,也值得了解一下。答案就寫在擴充功能的名字裡:WEBGL_debug_renderer_info 當初是為了偵錯而制定的。與特定硬體相關的算繪 Bug 真實存在,一個繪製大量 3D 內容的網站,確實有正當理由去記錄哪些 GPU/驅動程式組合會產出異常畫面。然而一個擴充功能一旦向整個 Web 平台開放,任何網站都能呼叫它,而不僅僅是真正有排查需求的那些——這正是絕大多數無需授權、卻高辨識度的指紋訊號背後的共同模式。
網站如何使用 WebGL 指紋
正當用途很常見。反詐騙與反機器人系統會把 WebGL 指紋作為眾多訊號之一,用來發現自動化流量、無頭瀏覽器,以及硬體突然變更的帳戶。分析與安全團隊用它來標記可疑工作階段。無頭與虛擬化環境常常暴露出標誌性的算繪器字串(例如 SwiftShader 或 llvmpipe 這類軟體點陣化器),這正是機器人偵測如此倚重 WebGL 的原因。
同樣的一致性邏輯不僅適用於 GPU,也延伸到瀏覽器本身:算繪器字串必須與環境中的其他資訊保持一致,包括實際繪製頁面的算繪引擎。你可以使用 BrowserInsight 的瀏覽器核心檢測查看自己的引擎及版本,並發現引擎偽裝的跡象。
同樣的能力也被用於跨站廣告與追蹤,因為一個以硬體為基礎的穩定 ID 能在清除 Cookie 與無痕視窗中存活下來。正是這種雙重用途,使得無論你關注的是安全還是隱私,理解 WebGL 指紋都很重要。
防禦手段及其取捨
沒有完美的防禦——每種方案都會以犧牲功能、效能或「融入人群」的能力為代價。主要思路如下:
Tor 瀏覽器
Tor 瀏覽器走的是標準化路線:它出廠時設定統一,使所有使用者呈現相同的指紋,並在允許 WebGL 之前先彈出視窗詢問。目標不是隱藏你的顯示卡,而是讓每個使用者看起來都一模一樣,這是最強的隱私模型——代價是速度下降以及部分 3D 內容失效。
Brave 與 Farbling
Brave 會對可指紋化的輸出(包括 WebGL 讀回結果)加入微小、確定性、且「依工作階段+依站點」變化的隨機擾動(稱為「farbling」)。每個站點看到的值都略有不同,且雜訊會重新洗牌,因此難以建構穩定的跨站 ID,而大多數頁面仍能正常運作。到了 Brave 1.93,這個思路也延伸到了中介資料層——廠商/算繪器去識別化與擴充功能清單隨機化的具體細節見上文「瀏覽器現在隱藏了什麼」。
完全停用 WebGL
透過開關或 webgl.disabled 徹底關閉 WebGL,會完全移除這一採集面。它有效但很「粗暴」:WebGL 的缺席本身就有幾分不尋常,還會讓地圖、遊戲與視覺化工具失效。
數值偽造——以及它為何會適得其反
覆寫算繪器字串或注入雜訊的擴充功能可能有幫助,但確有風險。若偽造的中介資料與算繪像素或數值上限相互矛盾,成熟的偵測器會察覺到這種不一致,於是你反而變得更易辨識,而非更難。最安全的偽造應當一致、且為眾多使用者所共用;缺乏協同、各使用者自行其是的隨機化,常常事與願違。
務實的結論是:選擇一個被許多人共用的防禦方案(Tor 的統一性、Brave 的 farbling),而不是一套讓你變得獨一無二的客製化設定。想了解自己目前的處境,請執行 BrowserInsight 的指紋偵測工具,查看你的 WebGL 算繪器、擴充功能與雜湊。
WebGL 也並非 GPU 指紋採集的終點。更新的 WebGPU API 將適配器廠商、架構和裝置字串作為一等屬性直接揭露——無需任何偵錯擴充功能。在不久前,它還是一個比 WebGL 更豐富、卻少有隱私工具涵蓋的採集面;Brave 1.93 透過清空這些適配器描述資訊關閉了它,其他瀏覽器目前仍會如實揭露這些資訊。
隨機化不等於匿名
以上防禦手段都無法讓你徹底「隱形」,這一點值得說清楚。一種讓你的瀏覽器變得罕見的防禦——一套沒有其他人共用的隨機化數值組合——可能和它原本想掩蓋的訊號一樣具有辨識度,原因和「獨自一人穿著奇裝異服反而更顯眼」如出一轍。我們在《Cover Your Tracks:唯一性評分證明不了什麼》中詳細討論了這種取捨及其應對思路。其背後的核心概念——需要多少人和你「長得一樣」,一個訊號才會失去重新辨識你的能力——則在《瀏覽器指紋的資訊熵與匿名集詳解》中有完整說明。統一性(Tor,以及現在 Brave 去識別化的廠商字串)之所以有效,是因為它讓你始終身處一大群人之中;而依使用者各自隨機化,只有當足夠多其他人也這麼做時才真正有幫助。
常見問題
網站能讀取我確切的顯示卡型號嗎?
這取決於你的瀏覽器。WEBGL_debug_renderer_info 擴充功能會暴露一條未遮罩的算繪器字串,常常點出你的 GPU 型號與算繪後端,在預設的 Chrome 或 Edge 設定下,它依然無需任何授權彈窗即可被讀取。Firefox 在開啟 privacy.resistFingerprinting 後會停用該擴充功能;而截至 Brave 1.93(2026 年 8 月),Brave 會把它換成所有 Brave 使用者共用的通用字串——完整的逐瀏覽器現況見上文「瀏覽器現在隱藏了什麼」。
隱私/無痕模式下 WebGL 指紋仍然有效嗎?
是的。無痕瀏覽會清除 Cookie 與歷史記錄,但不會改變你的硬體。WebGL 訊號——廠商、算繪器、擴充功能、數值上限與算繪雜湊——在一般視窗與無痕視窗中保持一致,因此能在兩者之間重新辨識你。
停用 WebGL 足以阻止指紋追蹤嗎?
它移除了 WebGL 這一採集面,但並未消除整體的指紋追蹤。Canvas、音訊、字型、螢幕等其他訊號依舊適用,而 WebGL 的顯眼缺席本身也可能成為一種區分特徵。停用它是一層防護,而非完整方案。
WebGL 指紋與 Canvas 指紋有何不同?
Canvas 指紋探測的是二維算繪路徑,而 WebGL 探測的是由 GPU 驅動的三維路徑,並額外暴露顯式的硬體中介資料(廠商、算繪器、能力上限)。兩者相關但不同,這正是追蹤者會同時採集二者以提高信賴度的原因。


