Cross-Origin-Opener-Policy (COOP) 标头
HTTP Cross-Origin-Opener-Policy (COOP) 响应标头允许网站控制是使用 Window.open() 打开的新顶级文档,还是通过导航到新页面,在相同的 浏览上下文组 (BCG) 中打开,还是在新的浏览上下文组中打开。
当在新的 BCG 中打开时,新文档与其打开者之间的任何引用都将断开,并且新文档可能会与其打开者进行进程隔离。这确保了潜在的攻击者无法使用 Window.open() 打开你的文档,然后使用返回的值访问其全局对象,从而防止了一系列被称为 XS-Leaks 的跨域攻击。
这也意味着由你的文档在新的 BCG 中打开的任何对象都不能使用 window.opener 访问它。这允许你对窗口引用拥有比 rel=noopener 更多的控制,后者影响传出导航,但不影响使用 Window.open() 打开的文档。
行为取决于新文档及其打开者的策略,以及新文档是随导航打开还是使用 Window.open() 打开。
语法
Cross-Origin-Opener-Policy: unsafe-none
Cross-Origin-Opener-Policy: same-origin-allow-popups
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Opener-Policy: noopener-allow-popups
指令
unsafe-none-
该文档允许与其他任何文档共享其浏览上下文组,因此可能不安全。它用于选择退出文档以使用 COOP 进行进程隔离。这是默认值。
在导航时,带有
unsafe-none的文档将始终在新的 BCG 中打开和被打开——除非其他文档也有unsafe-none(或没有 COOP 指令值)。使用
Window.open(),带有unsafe-none的文档将始终在新的 BCG 中打开带有任何其他值的文档。但是,如果打开者具有指令same-origin-allow-popups、noopener-allow-popups或unsafe-none,则带有unsafe-none的文档可以在相同的 BCG 中打开。带有same-origin的文档将始终在新的 BCG 中打开带有unsafe-none的文档。 same-origin-
该文档允许加载到使用 COOP 且仅包含同源文档的 BCG 中。这用于为 BCG 提供 跨域隔离。
带有
same-origin的文档仅在两个文档同源且都具有same-origin指令时才在相同的 BCG 中打开和被打开。 same-origin-allow-popups-
这类似于
same-origin指令,不同之处在于它允许在相同的 BCG 中打开使用Window.open()打开的文档,如果它们具有unsafe-none的 COOP 值。该指令用于放宽
same-origin限制,用于集成,其中文档需要跨域隔离的好处,但还需要打开并保留对受信任的跨域文档的引用。例如,当使用跨域服务进行 OAuth 或支付时。具有此指令的文档可以使用
Window.open()在相同的 BCG 中打开文档,如果它具有unsafe-none的 COOP 值。在这种情况下,打开的文档是跨站点还是同站点无关紧要。否则,带有
same-origin-allow-popups的文档仅在两个文档同源且都具有same-origin-allow-popups指令时才在相同的 BCG 中打开和被打开。 noopener-allow-popups-
带有此指令的文档始终在新 BCG 中打开,除非它们是通过从也具有
noopener-allow-popups的文档导航打开的。它用于支持需要进程隔离同源文档的情况。这会断开新文档与其打开者之间的连接,隔离当前文档的浏览上下文,无论打开者文档的来源如何。这确保了打开者不能在打开的文档中运行脚本,反之亦然——即使它们是同源的。
在导航时,带有此指令的文档将始终在新的 BCG 中打开其他文档,除非它们是同源的并且具有指令
noopener-allow-popups。使用Window.open(),带有此指令的文档将在新的 BCG 中打开文档,除非它们具有unsafe-none,在这种情况下,它们是同站点还是跨站点无关紧要。
描述
通常,你应该设置你的策略,使得只有同源和受信任的、需要能够相互脚本的跨域资源才允许在相同的浏览器上下文组中打开。其他资源应该在它们自己的组中进行跨域隔离。
以下部分显示了文档是随导航打开还是以编程方式打开窗口时,是在相同的 BCG 中打开还是在新的 BCG 中打开。
注意:规范使用术语“弹出窗口”来指代任何使用 Window.open() 打开的文档,无论它是弹出窗口、选项卡、窗口还是其他上下文。
导航
在文档之间导航时,如果两个文档具有“匹配的 COOP 策略”,则新文档在相同的 BCG 中打开,否则在新 BCG 中打开。
如果两个文档都具有 unsafe-none 策略,或者如果策略相同且文档同源,则策略匹配。
下表显示了此规则如何影响文档是打开在相同 BCG 还是新 BCG 中,对于不同的指令值。
| 打开者 (↓) / 被打开者 (→) | unsafe-none |
same-origin-allow-popups |
same-origin |
noopener-allow-popups |
|---|---|---|---|---|
unsafe-none |
相同 | 新的 | 新的 | 新的 |
same-origin-allow-popups |
新的 | 如果同源则相同 | 新的 | 新的 |
same-origin |
新的 | 新的 | 如果同源则相同 | 新的 |
noopener-allow-popups |
新的 | 新的 | 新的 | 如果同源则相同 |
使用 Window.open() 打开
当使用 Window.open() 打开文档时,新文档根据以下按顺序评估的规则在新 BCG 中打开:
- 如果新文档的 COOP 设置为
noopener-allow-popups=> 在新 BCG 中打开新文档 - 如果新文档的 COOP 设置为
unsafe-none并且打开者文档的 COOP 设置为same-origin-allow-popups或noopener-allow-popups=> 在相同的 BCG 中打开新文档 - 如果新文档和打开文档具有匹配的 COOP 策略 => 在相同的 BCG 中打开新文档
- 否则,在新 BCG 中打开新文档
下表显示了这些规则如何影响文档是打开在相同 BCG 还是新 BCG 中,对于不同的指令值。
| 打开者 (↓) / 被打开者 (→) | unsafe-none |
same-origin-allow-popups |
same-origin |
noopener-allow-popups |
|---|---|---|---|---|
unsafe-none |
相同 | 新的 | 新的 | 新的 |
same-origin-allow-popups |
相同 | 如果同源则相同 | 新的 | 新的 |
same-origin |
新的 | 新的 | 如果同源则相同 | 新的 |
noopener-allow-popups |
相同 | 新的 | 新的 | 新的 |
示例
依赖于跨域隔离的功能
某些功能,例如访问 SharedArrayBuffer 对象或使用 Performance.now() 与未节流计时器,仅在你的文档是跨域隔离时可用。
要在文档中使用这些功能,你需要将 COOP 标头设置为 same-origin,并将 Cross-Origin-Embedder-Policy 标头设置为 require-corp(或 credentialless)。此外,该功能不得被 Permissions-Policy: cross-origin-isolated 阻止。
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp
你可以使用 Window.crossOriginIsolated 和 WorkerGlobalScope.crossOriginIsolated 属性来检查文档是否已跨域隔离,从而确定这些功能是否受限。
const myWorker = new Worker("worker.js");
if (crossOriginIsolated) {
const buffer = new SharedArrayBuffer(16);
myWorker.postMessage(buffer);
} else {
const buffer = new ArrayBuffer(16);
myWorker.postMessage(buffer);
}
断开打开者关系
考虑一个假想的来源 example.com,它在同一来源上拥有两个截然不同的应用程序
- 一个位于
/chat的聊天应用程序,它允许任何用户联系其他任何用户并向他们发送消息。 - 一个位于
/passwords的密码管理应用程序,它包含用户在不同服务中的所有密码。
“密码”应用程序的管理员非常希望确保它不能被“聊天”应用程序直接脚本,因为“聊天”应用程序本质上具有更大的 XSS 攻击面。“正确”隔离这些应用程序的方法是将其托管在不同的来源上,但在某些情况下这不可能,并且由于历史、业务或品牌原因,这两个应用程序必须在单个来源上。
Cross-Origin-Opener-Policy: noopener-allow-popups 标头可用于确保文档不能被打开它的文档脚本化。
如果 example.com/passwords 以 noopener-allow-popups 提供服务,则 Window.open() 返回的 WindowProxy 将指示窗口已关闭(Window.closed 为 true),因此打开者无法脚本密码应用程序
const handle = window.open("example.com/passwords", "passwordTab");
if (windowProxy.closed) {
// The new window is closed so it can't be scripted.
}
请注意,这本身并不被认为是充分的安全措施。该网站还需要执行以下操作:
- 使用 Fetch Metadata 阻止对更敏感应用程序的非导航请求的同源请求。
- 确保其所有身份验证 Cookie 均为
HttpOnly。 - 确保不敏感应用程序未安装根级 Service-Workers。
- 确保更敏感应用程序上的
postMessage或BroadcastChannel不会向任何其他同源应用程序暴露任何敏感信息。 - 确保其登录页面在单独的来源上提供,因为密码管理器的自动填充是根据来源应用的。
- 了解浏览器仍可能将更敏感的应用程序分配到与不敏感应用程序相同的进程中,使其容易受到 Spectre 等攻击。
规范
| 规范 |
|---|
| HTML # COOP 标头 |
浏览器兼容性
加载中…