利用用户代理客户端提示改善用户隐私并提升开发者体验

用户代理客户端提示是对 Client Hints API 的新扩展,可让开发者以可保护隐私且符合人体工程学的方式访问用户浏览器的相关信息。

借助客户端提示,开发者可以主动请求有关用户设备或条件的信息,而无需从 User-Agent (UA) 字符串中解析这些信息。最终降低用户代理字符串粒度的第一步是提供此备用路由。

了解如何更新依赖于解析 User-Agent 字符串的现有功能,以便改用 User-Agent 客户端提示。

背景

当网络浏览器发出请求时,会包含有关浏览器及其环境的信息,以便服务器能够启用分析功能并自定义响应。它的定义早在 1996 年(HTTP/1.0 的 RFC 1945)中得到定义,您可以从中找到用户代理字符串的原始定义,其中包括一个示例:

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

此标头旨在按重要程度指定产品(例如浏览器或库)和注释(例如版本)。

User-Agent 字符串的状态

在过去的几十年里,此字符串积累了大量与发出请求的客户端相关的其他详细信息(以及由于向后兼容性而产生的垃圾内容)。在查看 Chrome 的当前用户代理字符串时,我们可以看到:

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 字符串支持许多合法用例,对开发者和网站所有者而言具有重要作用。不过,保护用户隐私免受隐秘跟踪方法的侵害同样至关重要,而默认发送 UA 信息与此目标背道而驰。

此外,还需要改进 User-Agent 字符串的 Web 兼容性。它是非结构化的,因此解析它会导致不必要的复杂性,这通常是导致 bug 和网站兼容性问题的原因,会给用户带来不良体验。这些问题还会严重损害使用不常用的浏览器的用户,因为网站可能未能针对其配置进行测试。

全新推出用户代理客户端提示

用户代理客户端提示可让您以更注重隐私保护的方式访问相同的信息,从而让浏览器最终减少用户代理字符串的默认广播所有信息的行为。客户端提示会强制执行一个模型,在该模型中,服务器必须请求浏览器提供有关客户端的一组数据(提示),然后浏览器会应用自己的政策或用户配置来确定返回哪些数据。这意味着,我们不再默认公开所有用户代理信息,而是现在以明确且可审核的方式管理访问权限。开发者还可以受益于更简单的 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 客户端提示

自 Chrome 89 起,用户代理客户端提示已默认启用。

默认情况下,浏览器会返回浏览器品牌、重要 / 主要版本、平台以及客户端是否为移动设备的指示器:

⬆️ 所有要求

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"

用户代理响应和请求标头

⬇️ 响应 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 中访问 User-Agent。您可以分别通过 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"
}

演示

您可以在自己的设备上访问 user-agent-client-hints.glitch.me,试用标头和 JavaScript API。

提示生命周期和重置

系统会在浏览器会话期间或在指定另一组提示之前,发送通过 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 标头指定每个提示和来源。如需将其应用于 User-Agent Client Hints,您需要将该提示转换为小写形式并移除 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 标头或使用访问相同信息的任何 JavaScript 调用(即 navigator.userAgentnavigator.appVersionnavigator.platform)的所有实例,以改用 User-Agent 客户端提示。

更进一步,您应重新审视自己对 User-Agent 信息的使用,并尽可能将其替换为其他方法。通常,您可以通过利用渐进增强、功能检测或自适应设计来实现相同的目标。依赖 User-Agent 数据的基本问题在于,您始终需要在要检查的媒体资源与其启用的行为之间维护映射。这项工作属于维护开销,旨在确保您的检测全面且保持最新状态。

考虑到这些注意事项,用户代理客户端提示代码库列出了一些网站的有效用例

用户代理字符串会怎样?

我们的计划是通过减少现有用户代理字符串公开的身份信息量,尽可能降低在网络上进行隐秘跟踪的可能性,同时不会对现有网站造成过多干扰。现在,我们推出了 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