運用使用者代理程式用戶端提示,改善使用者隱私和開發人員體驗

User-Agent Client Hints 是 Client Hints API 的新擴充功能,可讓開發人員以符合隱私權保護和人體工學的方式,存取使用者瀏覽器的相關資訊。

用戶端提示可讓開發人員主動要求有關使用者的裝置或條件的資訊,而不需要將其剖析出使用者代理程式 (UA) 字串。提供這個替代路徑是最終減少 User-Agent 字串精細程度的第一步。

瞭解如何更新現有的功能,以便改為使用 User-Agent Client Hints,而非解析 User-Agent 字串。

背景

網路瀏覽器提出要求時,會附上瀏覽器和環境的相關資訊,讓伺服器啟用數據分析功能並自訂回應內容。這個定義早在 1996 年就已定義 (RFC 1945 適用於 HTTP/1.0),您可以在該定義中找到「使用者代理程式」字串的原始定義,其中包含以下範例:

User-Agent: CERN-LineMode/2.15 libwww/2.17b3

這個標頭旨在依重要性順序指定產品 (例如瀏覽器或程式庫) 和註解 (例如版本)。

User-Agent 字串的狀態

在過去的數十年,這個字串累積了許多有關提出要求的用戶端的額外詳細資料 (以及因向下相容性而產生的垃圾資料)。查看 Chrome 目前的 User-Agent 字串,可以發現:

Mozilla/5.0 (Linux; Android 10; Pixel 3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4076.0 Mobile Safari/537.36

上述字串包含使用者的作業系統和版本、裝置型號、瀏覽器品牌與完整版本的相關資訊,足以推測出是行動瀏覽器,而不是為了歷史原因,提及其他瀏覽器的許多參照。

這些參數與可能值的多樣性相結合,表示 User-Agent 字串可能包含足夠的資訊,可用於明確識別個別使用者。

User-Agent 字串可用於許多合法的用途,並為開發人員和網站擁有者提供重要用途。不過,保護使用者隱私,避免使用隱密的追蹤方法,也是非常重要的一環,而預設傳送使用者代理程式資訊,就違背了這個目標。

使用者代理程式字串也需要提高網頁相容性。這並非結構化,因此剖析會產生不必要的複雜性,通常是因為錯誤和網站相容性問題,對使用者有害。這些問題也會對較不常見的瀏覽器使用者造成不成比例的影響,因為網站可能無法根據其設定進行測試。

全新推出使用者代理程式用戶端提示

使用者代理程式用戶端提示可讓使用者存取相同資訊,但能以更保護隱私權的方式存取,進而使瀏覽器最終減少 User-Agent 字串的預設廣播內容。用戶端提示會強制執行一種模式,其中伺服器必須向瀏覽器要求一組有關用戶端的資料 (提示),而瀏覽器會套用自身的政策或使用者設定,決定要傳回哪些資料。也就是說,系統現在會以明確且可稽核的方式管理存取權,而非預設方式公開所有 User-Agent 資訊。開發人員也能享有更簡單的 API 優勢,不再需要使用規則運算式!

目前的用戶端提示組合主要說明瀏覽器的顯示和連線功能。您可以參閱「使用用戶端提示自動選擇資源」一文,瞭解相關詳細資訊,但我們在此提供快速的程序重點。

伺服器會透過標頭要求特定的用戶端提示:

⬇️ 伺服器回應

Accept-CH: Viewport-Width, Width

或中繼標記:

<meta http-equiv="Accept-CH" content="Viewport-Width, Width" />

接著,瀏覽器可以選擇在後續要求中傳回下列標頭:

⬆️ 後續要求

Viewport-Width: 460
Width: 230

伺服器可以選擇變更回應內容,例如以適當解析度提供圖片。

使用者代理程式用戶端提示會使用 Sec-CH-UA 前置字,透過 Accept-CH 伺服器回應標頭指定屬性範圍。如需所有詳細資料,請先參閱說明,接著深入瞭解完整提案

來自 Chromium 89 的 User-Agent Client Hints

自 Chrome 89 版起,User-Agent Client Hints 已預設啟用。

根據預設,瀏覽器會傳回瀏覽器品牌、主要/主要版本、平台,以及客戶端是否為行動裝置的指標:

⬆️ 所有要求

Sec-CH-UA: "Chromium";v="93", "Google Chrome";v="93", " Not;A Brand";v="99"
Sec-CH-UA-Mobile: ?0
Sec-CH-UA-Platform: "macOS"

User-Agent 回應和要求標頭

⬇️ 回應 Accept-CH
⬆️ 要求標頭
⬆️ 要求
範例值
說明
Sec-CH-UA "Chromium";v="84",
"Google Chrome";v="84"
瀏覽器品牌和其重要版本的清單。
Sec-CH-UA-Mobile ?1 布林值,指出瀏覽器是否在行動裝置上 (?1 為 true) 或不在行動裝置上 (?0 為 false)。
Sec-CH-UA-Full-Version "84.0.4143.2" [已淘汰]瀏覽器的完整版本。
Sec-CH-UA-Full-Version-List "Chromium";v="84.0.4143.2",
"Google Chrome";v="84.0.4143.2"
瀏覽器品牌及其完整版本清單。
Sec-CH-UA-Platform "Android" 裝置平台,通常是作業系統 (OS)。
Sec-CH-UA-Platform-Version "10" 平台或作業系統的版本。
Sec-CH-UA-Arch "arm" 裝置的基礎架構。雖然這可能與顯示網頁無關,但網站可能會提供預設為正確格式的下載項目。
Sec-CH-UA-Model "Pixel 3" 裝置型號。
Sec-CH-UA-Bitness "64" 基礎架構的位元程度 (即整數或記憶體位址的大小,以位元為單位)

交換機示例

交換機器示例如下所示:

⬆️ 來自瀏覽器的初始要求
瀏覽器正在要求網站的 /downloads 頁面,並傳送預設的基礎 User-Agent。

GET /downloads HTTP/1.1
Host: example.site

Sec-CH-UA: "Chromium";v="93", "Google Chrome";v="93", " Not;A Brand";v="99"
Sec-CH-UA-Mobile: ?1
Sec-CH-UA-Platform: "Android"

⬇️ 伺服器回應
伺服器會傳回網頁,並要求提供完整的瀏覽器版本和平台。

HTTP/1.1 200 OK
Accept-CH: Sec-CH-UA-Full-Version-List

🎄?️ 後續要求
瀏覽器會授權伺服器存取其他資訊,並在所有後續要求中傳回額外提示。

GET /downloads/app1 HTTP/1.1
Host: example.site

Sec-CH-UA: " Not A;Brand";v="99", "Chromium";v="98", "Google Chrome";v="98"
Sec-CH-UA-Mobile: ?1
Sec-CH-UA-Full-Version-List: " Not A;Brand";v="99.0.0.0", "Chromium";v="98.0.4738.0", "Google Chrome";v="98.0.4738.0"
Sec-CH-UA-Platform: "Android"

JavaScript API

除了標頭外,您也可以透過 navigator.userAgentData 在 JavaScript 中存取使用者代理程式。您可以分別透過 brandsmobile 屬性存取預設的 Sec-CH-UASec-CH-UA-MobileSec-CH-UA-Platform 標頭資訊:

// Log the brand data
console.log(navigator.userAgentData.brands);

// output
[
  {
    brand: 'Chromium',
    version: '93',
  },
  {
    brand: 'Google Chrome',
    version: '93',
  },
  {
    brand: ' Not;A Brand',
    version: '99',
  },
];

// Log the mobile indicator
console.log(navigator.userAgentData.mobile);

// output
false;

// Log the platform value
console.log(navigator.userAgentData.platform);

// output
"macOS";

其他值可透過 getHighEntropyValues() 呼叫存取。換句話說,「高熵」一詞是指「資訊熵」的參照,也就是這些值提供給使用者瀏覽器的資訊量。如同要求其他標頭,瀏覽器會決定傳回哪些值 (如果有的話)。

// Log the full user-agent data
navigator
  .userAgentData.getHighEntropyValues(
    ["architecture", "model", "bitness", "platformVersion",
     "fullVersionList"])
  .then(ua => { console.log(ua) });

// output
{
   "architecture":"x86",
   "bitness":"64",
   "brands":[
      {
         "brand":" Not A;Brand",
         "version":"99"
      },
      {
         "brand":"Chromium",
         "version":"98"
      },
      {
         "brand":"Google Chrome",
         "version":"98"
      }
   ],
   "fullVersionList":[
      {
         "brand":" Not A;Brand",
         "version":"99.0.0.0"
      },
      {
         "brand":"Chromium",
         "version":"98.0.4738.0"
      },
      {
         "brand":"Google Chrome",
         "version":"98.0.4738.0"
      }
   ],
   "mobile":false,
   "model":"",
   "platformVersion":"12.0.1"
}

示範

您可以在自己的裝置上試用標頭和 JavaScript API,請前往 user-agent-client-hints.glitch.me

提示生命週期和重設

透過 Accept-CH 標頭指定的提示會在瀏覽器工作階段期間傳送,或直到指定不同的一組提示為止。

也就是說,如果伺服器傳送下列內容:

⬇️ 回覆

Accept-CH: Sec-CH-UA-Full-Version-List

接著,瀏覽器會對該網站的所有要求傳送 Sec-CH-UA-Full-Version-List 標頭,直到瀏覽器關閉為止。

⬆️ 後續要求

Sec-CH-UA-Full-Version-List: " Not A;Brand";v="99.0.0.0", "Chromium";v="98.0.4738.0", "Google Chrome";v="98.0.4738.0"

但是,如果收到另一個 Accept-CH 標頭,則會完全取代瀏覽器正在傳送的提示。

⬇️ 回覆

Accept-CH: Sec-CH-UA-Bitness

❌️ 後續要求

Sec-CH-UA-Platform: "64"

系統不會傳送先前要求的 Sec-CH-UA-Full-Version-List

最好將 Accept-CH 標頭視為指定該網頁所需的完整提示組合,這表示瀏覽器會為該網頁上的所有子資源傳送指定的提示。雖然提示會保留至下一次導覽,但網站不應依賴或假設會收到提示。

您也可以在回應中傳送空白 Accept-CH,藉此有效清除瀏覽器傳送的所有提示。建議您在使用者重設偏好設定或登出網站的任何位置加入這項功能。

這個模式也與透過 <meta http-equiv="Accept-CH" …> 標記顯示提示的方式相符。要求的提示只會在由網頁起始的要求時傳送,不會在任何後續瀏覽中傳送。

提示範圍和跨來源要求

根據預設,只有在相同來源要求時,系統才會傳送用戶端提示。也就是說,如果您在 https://example.com 上要求特定提示,但您要最佳化的資源位於 https://downloads.example.com,則這些資源不會收到任何提示。

如要允許跨來源要求的提示,則每個提示和來源都必須透過 Permissions-Policy 標頭指定。如要將其套用至使用者代理程式用戶端提示,您需要小寫提示,並移除 sec- 前置字串。例如:

⬇️ example.com 的回覆

Accept-CH: Sec-CH-UA-Platform-Version, DPR
Permissions-Policy: ch-ua-platform-version=(self "downloads.example.com"),
                    ch-dpr=(self "cdn.provider" "img.example.com");

⬆️ downloads.example.com收到的請款要求

Sec-CH-UA-Platform-Version: "10"

⬆️ 要求傳送至 cdn.providerimg.example.com

DPR: 2

使用 User-Agent Client Hints 的最佳位置

簡單來說,您應重構解析 User-Agent 標頭或使用任何存取相同資訊的 JavaScript 呼叫 (即 navigator.userAgentnavigator.appVersionnavigator.platform) 的任何例項,改為使用 User-Agent 用戶端提示。

進一步來說,您應重新檢查 User-Agent 資訊的使用方式,並盡可能以其他方法取代。一般來說,只要使用漸進式強化、特徵偵測或回應式設計,就能達成相同的目標。依賴 User-Agent 資料的基礎問題,就是您必須在要檢查的資源與啟用該資源的行為之間,一律維持對應關係。這項維護作業的目的,是確保偵測功能全面且保持最新狀態。

考量上述注意事項後,User-Agent Client Hints 存放區列出了網站的幾種有效用途。

User-Agent 字串會發生什麼事?

我們希望透過減少現有 User-Agent 字串洩漏的識別資訊量,盡可能減少網路上的隱密追蹤行為,同時不會對現有網站造成不必要的干擾。隆重推出「使用者代理程式用戶端提示」,您可以在對使用者代理程式字串進行任何變更之前,先瞭解並試用這項新功能。

最終,User-Agent 字串中的資訊將減少,以便維持舊版格式,同時只提供與預設提示相同的高階瀏覽器和重要版本資訊。在 Chromium 中,這項變更已延後到至少 2022 年,讓生態系統有時間評估新的使用者代理程式用戶端提示功能。

您可以透過啟用 Chrome 93 中的 about://flags/#reduce-user-agent 標記來測試這個版本 (注意:在 Chrome 84 至 92 版中,這個標記的名稱為 about://flags/#freeze-user-agent)。基於相容性因素,會傳回包含歷史項目的字串,但包含制化細節。例如:

Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.0.0 Mobile Safari/537.36

縮圖由 Unsplash 上的 Sergey Zolkin 提供