了解为什么需要跨域隔离才能使用 SharedArrayBuffer
、performance.measureUserAgentSpecificMemory()
和精确度更高的高分辨率计时器等强大功能。
简介
在使用 COOP 和 COEP 将网站设置为“跨域隔离”中,我们介绍了如何使用 COOP 和 COEP 采用“跨域隔离”状态。本文是另一篇配套文章,解释了为何需要跨域隔离才能在浏览器中启用强大的功能。
背景
Web 基于同源政策构建,同源政策是一项安全功能,用于限制文档和脚本与其他来源的资源交互方式。此原则会限制网站访问跨源资源的方式。例如,系统阻止 https://a.example
中的文档访问 https://b.example
上托管的数据。
不过,同源政策也有一些历史例外情况。任何网站都可以:
- 嵌入跨源 iframe
- 包含图片或脚本等跨源资源
- 使用 DOM 引用打开跨源弹出式窗口
如果网页可以从头开始设计,这些例外情况就不会存在。遗憾的是,当网络社区认识到严格同源政策的主要好处时,网络已经在依赖这些例外。
我们通过两种方式解决了这种宽松的同源政策的安全副作用。一种方法是通过引入一种名为跨域资源共享 (CORS) 的新协议,该协议的目的是确保服务器允许与给定来源共享资源。另一种方法是隐式移除脚本对跨源资源的直接访问,同时保持向后兼容性。此类跨源资源称为“不透明”资源。例如,这就是为什么除非对跨源图片应用 CORS,否则通过 CanvasRenderingContext2D
操控跨源图片的像素会失败。
所有这些政策决策都是在浏览上下文组中做出。
很长一段时间以来,CORS 和不透明资源的组合足以确保浏览器的安全性。有时,虽然发现了边缘情况(例如 JSON 漏洞),因此需要进行修补,但总体而言,不允许直接读取跨源资源的原始字节的原则是成功的。
这些都通过 Spectre 进行了改变,它会使加载到与您的代码相同的浏览上下文组的任何数据都可能被读取。通过测量特定操作花费的时间,攻击者可以猜测 CPU 缓存的内容,进而猜测出进程内存的内容。此类计时攻击可通过平台中存在的低粒度计时器实现,但可以通过高粒度计时器(显式(如 performance.now()
)和隐式(如 SharedArrayBuffer
))加速。如果 evil.com
嵌入了跨源图像,它们可以使用 Spectre 攻击来读取其像素数据,这会导致依赖于“不透明”的保护失效。
理想情况下,所有跨源请求都应由拥有相应资源的服务器进行明确审查。如果资源拥有服务器未提供审查功能,则数据永远不会进入邪恶行为者的浏览上下文组中,因此也不会受到网页可能执行的任何 Spectre 攻击。我们称之为跨域隔离状态。这正是 COOP+COEP 的用武之地。
在跨域隔离状态下,发出请求的网站的危险性较低,这可以解锁 SharedArrayBuffer
、performance.measureUserAgentSpecificMemory()
和高分辨率计时器等强大功能,并且这些功能准确性更高,否则可能会用于类似 Spectre 的攻击。它还可以阻止修改 document.domain
。
跨域嵌入器政策
跨域嵌入器政策 (COEP) 可防止文档加载任何未明确授予文档权限的跨源资源(使用 CORP 或 CORS)。借助此功能,您可以声明文档无法加载此类资源。
若要启用此政策,请将以下 HTTP 标头附加到文档:
Cross-Origin-Embedder-Policy: require-corp
require-corp
关键字是 COEP 唯一可接受的值。这会强制实施如下政策:文档只能从同一来源加载资源,或者只能从另一个来源加载资源。
对于可从其他来源加载的资源,它们需要支持跨域资源共享 (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
。
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
来选择停用隔离。
Cross-Origin-Opener-Policy: unsafe-none
unsafe-none
是默认值,允许将文档添加到其打开器的浏览上下文组中,除非该打开器本身的 COOP 为 same-origin
。
摘要
如果您希望确保能够使用准确性更高的 SharedArrayBuffer
、performance.measureUserAgentSpecificMemory()
或高分辨率计时器等强大功能,请记住,您的文档需要同时使用值为 require-corp
的 COEP 和值为 same-origin
的 COOP。如果缺少其中任何一种,浏览器将无法保证足够的隔离来安全地启用这些强大的功能。您可以通过检查 self.crossOriginIsolated
是否返回 true
来确定网页的情况。
如需了解实现此操作的步骤,请参阅使用 COOP 和 COEP 将网站设置为“跨域隔离”。