navigator.hardwareConcurrency 與 deviceMemory 回報什麼、為何刻意粗化,以及網站如何藉它們識破不合常理的裝置聲明。
JavaScript 裡兩行程式碼,就能讓頁面大致知道你的裝置有多強:有多少個邏輯處理器,以及大約多少記憶體。單獨看,這兩個數字都不稀奇;合在一起,訪客就被歸入某個裝置等級:入門手機、辦公筆電、工作站。本文說明每個值的含義、瀏覽器如何刻意把它們模糊化,以及它們最主要的用途——檢查所宣稱的裝置是否可信。
重點摘要
navigator.hardwareConcurrency回報可用來執行執行緒的邏輯處理器數量,瀏覽器回報的數字可能比機器實際擁有的更小。navigator.deviceMemory回報以 GiB 計的近似記憶體,向 2 的冪次取整,並被限制在由實作自行決定的上下界之內。它是 Chromium 一側的 API,別指望每個瀏覽器都有。- 這兩個值在設計上都是低熵的。它們的分量來自與螢幕尺寸、GPU、平台的組合,計算方法見指紋熵與匿名集。
- 它們最適合做一致性檢查:裝置在 User-Agent 裡宣稱一個等級、在這裡回報另一個等級,就是自相矛盾。
- BrowserInsight 依瀏覽器的原樣顯示這兩個值;其機器人偵測只做簡單的範圍檢驗,並不會拿它們去對照你的 User-Agent。
這兩個 API 為什麼存在
它們都不是為追蹤而設計的,而是讓頁面適配執行它的裝置。
hardwareConcurrency 的用途是決定 Web Worker 執行緒池的大小。MDN 的 hardwareConcurrency 頁面給出的範例正是:每個回報的邏輯處理器對應一個 Worker。裝置記憶體規範 W3C Device Memory 則把它描述為一種「裝置等級訊號」,用於替低階裝置提供更輕量的網站版本,以及正規化效能指標,讓同樣一次長任務在弱裝置和強裝置上得到不同的解讀。
hardwareConcurrency:是邏輯處理器,不是核心數
MDN 將該值定義為使用者電腦上可用於執行執行緒的邏輯處理器數量,範圍從 1 到瀏覽器可能用到的最大數量。有兩點要注意:
- 邏輯的,而非實體的。 一顆每核兩執行緒的四核 CPU 可以回報 8。你看到的數字不是核心數。
- 可能被調低。 MDN 指出,瀏覽器可以回報更小的數字,以更準確地表示同時能執行多少個 Worker,所以它不是對硬體的絕對度量。我們這裡不羅列各瀏覽器的具體調整規則,因為 MDN 沒有寫死,而且會變動;請到該頁面的相容性表查看目標瀏覽器。
真實機器上的常見取值集中在 4、8、12、16 這類常見數值,所以單看這個數字幾乎區分不了什麼。讀數為 2 和讀數為 24 當然也能把訪客分開,但只是分成很寬的幾大群。
deviceMemory:刻意做粗
Device Memory API 的設計本意就是不精確。依據規範和 MDN 的 deviceMemory 頁面:
- 該值是實體記憶體向 2 的冪次取整後以 GiB 表示的結果,所以你得到的是 2、4、8 這樣的數字,而不是「7.6」。
- 隨後會被限制在實作自訂的下界和上界之間,目的是不暴露極少見的超低或超高記憶體規格。規範說明實作可以隨時間調整這些界限,且不同裝置類型可以不同。MDN 自己的範例假設瀏覽器不回報低於 2 或高於 32 的值,得到 2、4、8、16 或 32。這只是示例,不是通用規則。
- 它只在安全環境(HTTPS)中可用。
伺服器不執行任何指令碼也能收到同一數值,途徑是 Sec-CH-Device-Memory 用戶端提示。它需要主動開啟:伺服器須先送出 Accept-CH: Sec-CH-Device-Memory,且 MDN 將該請求標頭標為實驗性。這條標頭路徑與其他提示的關係,見 User-Agent Client Hints。
各家支援並不一致。Safari 和 Firefox 不提供 deviceMemory,所以那裡缺少該值很正常,會顯示為「未知」,絕不當作危險訊號。不過「沒有這個屬性」本身,也會向頁面透露一點引擎資訊。
兩個小數字為何仍然重要
拿一個典型的取值組合,問問有多少訪客與你相同。答案是很多,這正是任何一個單獨的值都不是好識別碼的原因。風險出現在它們與幾十種其他訊號疊加時,例如螢幕幾何、GPU 渲染器和平台;每多一個,人群就被切得更小。匿名集的算法說明少量低熵位元是怎樣累加的,瀏覽器指紋指南則列出了這兩項在全部訊號中的位置。
它們更重要的用途:一致性
弱識別碼也可以是強力的測謊儀。這些值應當與瀏覽器宣稱的裝置相符:
- 桌面 Windows 的 User-Agent 卻回報 2 個邏輯處理器和最低的記憶體級距,對現代機器來說不尋常,但並非不可能。
- 行動端 User-Agent 回報幾十個邏輯處理器,或超過任何手機的記憶體數字,顯示可能是模擬或虛擬化環境。
- iPhone 的 User-Agent 卻提供了
deviceMemory值就很奇怪,因為 WebKit 不提供這個 API。 - 數百個「不同」的訪客擁有完全相同的核心數、記憶體級距和螢幕尺寸,看起來像同一個映像檔被複製了很多份。這正是雲手機偵測背後的聚合模式。
這些單獨都不構成證明,它們會與其他矛盾一起加權,例如指紋硬體錯配裡不可能的 GPU 與作業系統組合、無頭瀏覽器偵測中的自動化線索,以及指紋一致性的整體原則。
隱私工具如何處理
強化模式會把精確的硬體值換成通用值,讓群體中的每個人看起來都一樣。例如 Firefox 的 resist-fingerprinting 模式會把 navigator.hardwareConcurrency 偽裝成固定值;resist-fingerprinting 詳解討論了其中的取捨,包括偶爾會有網站因遇到意外取值而出問題。目標是擴大匿名集,而不是造一個可信的假數:隨機編出來的數字可能和真值一樣有辨識度。在請求標頭一側,瀏覽器只有在伺服器主動開啟後才會送出 Sec-CH-Device-Memory,而且該值本來就很粗。
BrowserInsight 實際做了什麼
直說兩件事。指紋檢測依瀏覽器的原樣顯示 hardwareConcurrency 和 deviceMemory,API 不存在時顯示「未知」。機器人偵測頁面執行一項 hardware_limit 合理性檢查,只判斷已有的值是否落在合理範圍內(核心數 1 到 64,記憶體不超過 64 GiB),不會拿它們去對照你的 User-Agent 或 GPU。所有蒐集都在你的瀏覽器內完成,不會向伺服器傳送任何資料。
常見問題
hardwareConcurrency 就是 CPU 核心數嗎? 不是。它統計的是邏輯處理器,數量可能是實體核心的兩倍,而且瀏覽器可以回報更小的數字。
為什麼我的 deviceMemory 從來不是 6 或 12? 這個值在回報前就向 2 的冪次取整,所以介於兩級之間的容量會落到相鄰的一級。
網站不用 JavaScript 能讀到我的記憶體嗎?
只能透過 Sec-CH-Device-Memory 用戶端提示,而且前提是伺服器用 Accept-CH 提出了請求、你的瀏覽器也支援。
僅憑這個就能追蹤我嗎? 單靠它不行。只有與許多其他訊號組合,它對追蹤者才有用。
結語
hardwareConcurrency 和 deviceMemory 是刻意做得很克制的訊號:一個粗略的處理器數量,一個取整後的記憶體級距。它們的實際價值在於檢驗所宣稱的裝置是否合理,以及替更大的指紋增加幾個位元。你可以在指紋檢測裡查看自己的瀏覽器回報了什麼,看看其餘設定是否講著同一個故事。


