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() 開啟。

頭型別 響應頭
禁止請求頭

語法

http
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-popupsnoopener-allow-popupsunsafe-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 中開啟:

  1. 如果新文件的 COOP 設定為 noopener-allow-popups => 在新 BCG 中開啟新文件
  2. 如果新文件的 COOP 設定為 unsafe-none 並且開啟者文件的 COOP 設定為 same-origin-allow-popupsnoopener-allow-popups => 在相同的 BCG 中開啟新文件
  3. 如果新文件和開啟文件具有匹配的 COOP 策略 => 在相同的 BCG 中開啟新文件
  4. 否則,在新 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 阻止。

http
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp

你可以使用 Window.crossOriginIsolatedWorkerGlobalScope.crossOriginIsolated 屬性來檢查文件是否已跨域隔離,從而確定這些功能是否受限。

js
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/passwordsnoopener-allow-popups 提供服務,則 Window.open() 返回的 WindowProxy 將指示視窗已關閉(Window.closedtrue),因此開啟者無法指令碼密碼應用程式

js
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。
  • 確保更敏感應用程式上的 postMessageBroadcastChannel 不會向任何其他同源應用程式暴露任何敏感資訊。
  • 確保其登入頁面在單獨的來源上提供,因為密碼管理器的自動填充是根據來源應用的。
  • 瞭解瀏覽器仍可能將更敏感的應用程式分配到與不敏感應用程式相同的程序中,使其容易受到 Spectre 等攻擊。

規範

規範
HTML
# COOP 標頭

瀏覽器相容性

另見