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