为什么需要“跨源隔离”来实现强大的功能

了解为何需要跨源隔离,才能使用 SharedArrayBufferperformance.measureUserAgentSpecificMemory() 和高分辨率计时器等功能,并提高精确性。

使用 COOP 和 COEP 将您的网站设为“跨源隔离”状态一文中,我们介绍了如何使用 COOP 和 COEP 采用“跨源隔离”状态。本文是配套文章,介绍了为何需要跨源隔离才能在浏览器中启用强大的功能。

背景

网络是基于同源政策构建的:这项安全功能会限制文档和脚本与其他来源的资源的互动方式。此原则限制了网站访问跨源资源的方式。例如,https://a.example 中的文档将被禁止访问托管在 https://b.example 中的数据。

不过,同源政策在历史上有一些例外情况。任何网站都可以:

  • 嵌入跨源 iframe
  • 包含跨源资源,例如图片或脚本
  • 使用 DOM 引用打开跨源弹出式窗口

如果网站可以从头开始设计,这些例外情况就不会存在。 遗憾的是,当网络社区意识到严格的同源政策的主要优势时,网络已经在依赖这些例外情况。

我们通过两种方式修补了这种宽松的同源政策带来的安全副作用。其中一种方法是引入一种名为跨源资源共享 (CORS) 的新协议,其目的是确保服务器允许与给定来源共享资源。另一种方法是隐式移除对跨源资源的直接脚本访问,同时保留向后兼容性。此类跨源资源称为“不透明”资源。例如,这就是为什么除非对图片应用 CORS,否则通过 CanvasRenderingContext2D 操控跨源图片的像素会失败。

所有这些政策决策都在浏览情境组内进行。

浏览情境组

长久以来,CORS 和不透明资源的组合就足以确保浏览器的安全。有时,我们会发现极端情况(例如 JSON 漏洞),需要进行修补,但总体而言,不允许直接读取跨源资源的原始字节的原则取得了成功。

这一切都随着 Spectre 的出现而发生了变化,它会使加载到与您的代码相同的浏览器上下文组的所有数据都有可能被读取。通过测量某些操作所需的时间,攻击者可以猜测 CPU 缓存的内容,进而猜测进程内存的内容。平台中存在的低精度计时器可能会导致此类定时攻击,但可以通过高精度计时器(包括显式计时器 [例如 performance.now()] 和隐式计时器 [例如 SharedArrayBuffer])加快攻击速度。如果 evil.com 嵌入了跨源图片,攻击者可以使用 Spectre 攻击来读取其像素数据,这会使依赖于“不透明性”的保护措施无效。

Spectr

理想情况下,所有跨源请求都应由拥有资源的服务器明确审核。如果资源所有者服务器未提供审核,则数据将永远不会进入恶意行为者的浏览上下文组,因此将不会受到网页可能执行的任何 Spectre 攻击的影响。我们将其称为跨源隔离状态。这正是 COOP+COEP 的意义所在。

在跨源隔离状态下,请求网站被视为不太危险,这解锁了 SharedArrayBufferperformance.measureUserAgentSpecificMemory()高分辨率计时器等功能,这些功能的精度更高,否则可能会被用于 Spectre 等攻击。它还会阻止修改 document.domain

跨源嵌入器政策

跨源嵌入者政策 (COEP) 会阻止文档加载未明确授予文档权限(使用 CORP 或 CORS)的任何跨源资源。借助此功能,您可以声明文档无法加载此类资源。

COEP 的运作方式

如需启用此政策,请将以下 HTTP 标头附加到文档中:

Cross-Origin-Embedder-Policy: require-corp

COEP 采用单个值 require-corp。这会强制执行以下政策:文档只能加载来自同一源的资源,或者明确标记为可从其他源加载的资源。

若要从其他来源加载资源,这些资源需要支持跨源资源共享 (CORS) 或跨源资源政策 (CORP)。

跨源资源共享

如果跨源资源支持跨源资源共享 (CORS),您可以使用 crossorigin 属性将其加载到网页中,而不会被 COEP 屏蔽。

<img src="https://third-party.example.com/image.jpg" crossorigin>

例如,如果此图片资源使用 CORS 标头提供,请使用 crossorigin 属性,以便提取资源的请求将使用 CORS 模式。这还会阻止加载图片,除非它设置了 CORS 标头。

同样,您可以通过 fetch() 方法提取跨源数据,只要服务器使用正确的 HTTP 标头做出响应,就无需进行特殊处理。

跨源资源政策

跨源资源政策 (CORP) 最初是作为一种可选功能引入的,旨在保护您的资源免遭其他来源加载。在 COEP 上下文中,CORP 可以指定资源所有者的政策,以确定谁可以加载资源。

Cross-Origin-Resource-Policy 标头有三个可能的值:

Cross-Origin-Resource-Policy: same-site

标记为 same-site 的资源只能从同一网站加载。

Cross-Origin-Resource-Policy: same-origin

标记为 same-origin 的资源只能从同一来源加载。

Cross-Origin-Resource-Policy: cross-origin

标记为 cross-origin 的资源可供任何网站加载。(此值已与 COEP 一起添加到 CORP 规范中。)

跨源打开者政策

借助跨源开放者政策 (COOP),您可以将其他文档放入不同的浏览上下文组,以确保顶级窗口与其他文档隔离,这样其他文档便无法直接与顶级窗口互动。例如,如果包含 COOP 的文档打开弹出式窗口,则其 window.opener 属性将为 null。此外,打开器对其的引用的 .closed 属性将返回 true

COOP

Cross-Origin-Opener-Policy 标头有三个可能的值:

Cross-Origin-Opener-Policy: same-origin

标记为 same-origin 的文档可以与也明确标记为 same-origin 的同源文档共享同一浏览上下文组。

COOP

Cross-Origin-Opener-Policy: same-origin-allow-popups

包含 same-origin-allow-popups 的顶级文档会保留对其任何弹出式窗口的引用,这些弹出式窗口要么未设置 COOP,要么通过将 COOP 设置为 unsafe-none 而选择停用隔离。

COOP

Cross-Origin-Opener-Policy: unsafe-none

unsafe-none 是默认值,允许将文档添加到其打开器的浏览上下文组,除非打开器本身的 COOP 为 same-origin

摘要

如果您想保证能够使用 SharedArrayBufferperformance.measureUserAgentSpecificMemory()高分辨率计时器等功能,并获得更高的精确度,请务必注意,您的文档需要同时使用值为 require-corp 的 COEP 和值为 same-origin 的 COOP。如果缺少其中任一项,浏览器将无法保证足够的隔离,无法安全地启用这些强大的功能。您可以通过检查 self.crossOriginIsolated 是否返回 true 来确定网页的状态。

如需了解实现此功能的步骤,请参阅使用 COOP 和 COEP 使您的网站实现“跨源隔离”

资源