通过对缓存进行分区,确保安全性和隐私保护

Eiji Kitamura
北村英二

一般来说,缓存可以通过存储数据来提高性能,这样将来针对相同数据的请求可以更快地得到处理。例如,通过网络缓存资源可以避免往返服务器。缓存的计算结果可以省略执行相同计算所需的时间。

在 Chrome 中,缓存机制以各种方式使用,HTTP 缓存便是一个示例。

Chrome 的 HTTP 缓存目前的运作方式

从版本 85 开始,Chrome 会缓存从网络获取的资源,并将各自的资源网址用作缓存键。(缓存键用于标识缓存的资源)。

以下示例展示了如何在三种不同的上下文中缓存和处理单张图片:

缓存键:https://x.example/doge.png
缓存键:{ https://x.example/doge.png }

用户访问请求图片 (https://x.example/doge.png) 的页面 (https://a.example)。该图片从网络请求,并使用 https://x.example/doge.png 作为键进行缓存。

缓存键:https://x.example/doge.png
缓存键:{ https://x.example/doge.png }

同一用户访问请求同一图片 (https://x.example/doge.png) 的另一个页面 (https://b.example)。浏览器会使用图片网址作为键,检查其 HTTP 缓存以查看是否已缓存此资源。浏览器会在自身的缓存中找到匹配项,因此会使用该资源的缓存版本。

缓存键:https://x.example/doge.png
缓存键:{ https://x.example/doge.png }

图片是否从 iframe 中加载无关紧要。如果用户使用 iframe (https://d.example) 访问其他网站 (https://c.example),并且该 iframe 请求同一图片 (https://x.example/doge.png),则浏览器仍然可以从缓存中加载该图片,因为所有网页的缓存键都相同。

长期以来,此机制从性能的角度来看一直有效。但是,网站响应 HTTP 请求所需的时间可以看出浏览器之前访问过同一资源,这会导致浏览器遭受安全和隐私攻击,如下所示:

  • 检测用户是否访问过特定网站:攻击者可以通过检查缓存是否包含特定网站或网站同类群组特有的资源,来检测用户的浏览记录。
  • 跨网站搜索攻击:攻击者可以检查浏览器缓存中是否包含特定网站使用的“无搜索结果”图片,从而检测用户搜索结果中是否包含任意字符串。
  • 跨网站跟踪:缓存可用于存储类似于 Cookie 的标识符,作为跨网站跟踪机制。

为了缓解这些风险,Chrome 将从 Chrome 86 开始对其 HTTP 缓存进行分区。

缓存分区对 Chrome 的 HTTP 缓存有何影响?

借助缓存分区,系统将使用新的“网络隔离键”以及资源网址对缓存的资源进行键控。网络隔离键由顶级网站和当前框架网站组成。

再次查看上一个示例,了解缓存分区在不同上下文中的工作原理:

缓存键 { https://a.example, https://a.example, https://x.example/doge.png}
缓存键:{ https://a.example, https://a.example, https://x.example/doge.png }

用户访问请求图片 (https://x.example/doge.png) 的页面 (https://a.example)。在本例中,从网络请求图片并使用由 https://a.example(顶级网站)、https://a.example(当前框架网站)和 https://x.example/doge.png(资源网址)作为键组成的元组进行缓存。(请注意,当资源请求来自顶级框架时,网络隔离键中的顶级网站和当前框架网站是相同的。)

缓存键 { https://a.example, https://a.example, https://x.example/doge.png}
缓存键:{ https://b.example, https://b.example, https://x.example/doge.png }

同一用户访问请求同一图片 (https://x.example/doge.png) 的不同页面 (https://b.example)。虽然在上一个示例中加载了同一图片,但由于键不匹配,它就不会成为缓存命中。

从网络请求图像并使用由 https://b.examplehttps://b.examplehttps://x.example/doge.png 作为键组成的元组进行缓存。

缓存键 { https://a.example, https://a.example, https://x.example/doge.png}
缓存键:{ https://a.example, https://a.example, https://x.example/doge.png }

现在,用户返回到 https://a.example,但这次图片 (https://x.example/doge.png) 嵌入在 iframe 中。在本例中,键是包含 https://a.examplehttps://a.examplehttps://x.example/doge.png 的元组,并且会发生缓存命中。(请注意,当顶级网站和 iframe 是同一个网站时,可以使用通过顶级框架缓存的资源。

缓存键 { https://a.example, https://a.example, https://x.example/doge.png}
缓存键:{ https://a.example, https://c.example, https://x.example/doge.png }

用户返回 https://a.example,但这次图片托管在来自 https://c.example 的 iframe 中。

在这种情况下,系统会从网络下载映像,因为缓存中没有与由 https://a.examplehttps://c.examplehttps://x.example/doge.png 组成的键匹配的资源。

缓存键 { https://a.example, https://a.example, https://x.example/doge.png}
缓存键:{ https://a.example, https://c.example, https://x.example/doge.png }

如果域名包含子域名或端口号,该怎么办?用户访问了 https://subdomain.a.example,其中嵌入了请求图片的 iframe (https://c.example:8080)。

由于密钥是基于“scheme://eTLD+1”创建的,因此子网域和端口号会被忽略。所以会发生缓存命中。

缓存键 { https://a.example, https://a.example, https://x.example/doge.png}
缓存键:{ https://a.example, https://c.example, https://x.example/doge.png }

如果 iframe 嵌套多次会怎样?用户访问了 https://a.example,它嵌入了一个 iframe (https://b.example),而另一个 iframe (https://c.example) 最终会请求图片。

由于键取自顶级帧 (https://a.example) 和加载资源的即时帧 (https://c.example),因此会发生缓存命中。

常见问题解答

我的 Chrome 上已经启用了该功能吗?该如何确认?

此功能会持续到 2020 年底。如需检查您的 Chrome 实例是否已支持该功能,请执行以下操作:

  1. 打开 chrome://net-export/,然后按开始记录到磁盘
  2. 指定在计算机中的什么位置保存日志文件。
  3. 花一分钟时间在 Chrome 上浏览网页。
  4. 返回 chrome://net-export/,然后按停止日志记录
  5. 转到 https://netlog-viewer.appspot.com/#import
  6. 选择文件,然后传递您保存的日志文件。

您将看到日志文件的输出。

在同一页面上,找到 SplitCacheByNetworkIsolationKey。如果后跟 Experiment_[****],则表示 Chrome 上会启用 HTTP 缓存分区。如果后跟 Control_[****]Default_[****],则表示它未启用。

如何在 Chrome 上测试 HTTP 缓存分区?

如需在 Chrome 上测试 HTTP 缓存分区,您需要使用命令行标志 --enable-features=SplitCacheByNetworkIsolationKey 启动 Chrome。请按照使用标志运行 Chromium 中的说明,了解如何在您的平台上使用命令行标志启动 Chrome。

作为 Web 开发者,我是否应该针对这一变更采取任何行动?

这不是破坏性更改,但可能会给某些网络服务带来性能方面的考量。

例如,如果网站跨多个网站(例如字体和热门脚本)提供大量高度可缓存的资源,其流量可能会增加。此外,使用此类服务的用户可能对这些服务的依赖程度更高。

(我们提议以可保护隐私的方式启用共享库,即 Web 共享库演示视频),但此方案仍在考虑中。)

这一行为变更产生了什么影响?

整体缓存未命中率增加了约 3.6%,对 FCP(首次内容渲染)的更改相对较小(约 0.3%),从网络加载的总字节数增加了约 4%。如需详细了解对性能的影响,请参阅 HTTP 缓存分区解释器

这是标准化的吗?其他浏览器的行为是否有所不同?

“HTTP cache 分区”已在抓取规范中进行了标准化,但浏览器的行为方式有所不同:

如何处理从 worker 中提取数据?

专用工作器使用与其当前帧相同的密钥。Service Worker 和共享 worker 可能由多个顶级网站共享,因此更为复杂。针对他们的解决方案目前正在讨论中。

资源