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

发布日期:2020 年 5 月 4 日

使用 COOP 和 COEP 使您的网站“跨域隔离”中,我们介绍了如何使用 COOP 和 COEP 采用“跨域隔离”状态。这是一篇配套文章,其中说明了为什么需要进行跨源隔离才能在浏览器上启用强大的功能。

术语表

本文档使用了许多名称相似且缩写的术语。为明确起见,我们整理了一份迷你词汇表:

背景

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

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

  • 嵌入跨源 iframe
  • 包含图片或脚本等跨源资源
  • 使用 DOM 引用打开跨源对话框窗口

当 Web 社区意识到严格的同源政策的好处时,Web 已经依赖于这些例外情况。

我们通过以下两种方式修补了这种宽松的同源政策带来的安全副作用:

  • 跨源资源共享 (CORS) 协议可确保服务器允许与指定来源共享资源。
  • 开发者隐式移除了对跨源资源的直接脚本访问权限,同时保留了向后兼容性。此类跨源资源称为“不透明”资源。这就是为什么使用 CanvasRenderingContext2D 进行跨源像素操作会失败,除非对图片应用 CORS。

所有这些政策决策都是在浏览上下文组中做出的。

浏览上下文组包含主要网站和嵌入网站中的素材资源。

在很长一段时间内,这种组合足以确保浏览器安全,只有少数边缘情况需要直接修补(例如 JSON 漏洞)。

Spectre 改变了这一点,它可能会读取加载到与您的代码相同的浏览上下文组中的任何数据。通过测量某些操作所花费的时间,攻击者可以猜测 CPU 缓存的内容,进而猜测进程内存的内容。此类攻击可以通过平台中存在的低粒度计时器实现,并且可以通过显式(例如 performance.now())和隐式(例如 SharedArrayBuffer)高粒度计时器来加速。

如果 evil.com 嵌入了跨源图片,攻击者可以使用 Spectre 攻击来读取嵌入图片的像素数据。这会使依赖“不透明度”的保护措施失效。

evil.com 是主网站,通过使用 Spectre 攻击嵌入的 b.example iframe 和图片。

理想情况下,所有跨源请求都应由资源所属的服务器进行审查。如果未执行审查,则数据绝不应进入恶意行为者的浏览上下文组。因此,数据不会受到可能的 Spectre 攻击。我们将此称为跨域隔离状态

当嵌入的代码处于跨源隔离状态时,请求网站被认为不太危险。这样,请求网站就可以使用精度更高的 SharedArrayBufferperformance.measureUserAgentSpecificMemory()高分辨率计时器,同时防止可能的 Spectre 攻击。此状态还会阻止修改 document.domain

跨源嵌入器政策

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

一张图表,显示了哪些嵌入式资源因 CORP 政策而允许和不允许。
父网站 a.example 将 COEP 政策设置为 require-corpa.example 想要嵌入 b.example 中的 3 个素材资源,但只有 2 个成功嵌入。 两个成功的嵌入包括一个具有跨源 CORP 政策的 JavaScript 文件和一个允许 CORS 的图片。第三个素材资源是一段视频,该视频具有 CORP 政策,要求素材资源只能嵌入到同源网页中,因此该视频不会加载到 a.example 上。

如需激活此政策,请将以下 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

a.example 无法在对话框中打开 b.example。

Cross-Origin-Opener-Policy 标头可采用以下三个值:

Cross-Origin-Opener-Policy: same-origin

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

该图描绘了一个能够与“同源”弹出式窗口互动的窗口,该弹出式窗口位于同一浏览上下文组中,但未标记为“同源”,同时仍位于浏览上下文组之外。

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 使您的网站“跨源隔离”

资源