使用 COOP 和 COEP 建立網站 "跨來源隔離

使用 COOP 和 COEP 設定跨來源隔離環境,並啟用 SharedArrayBufferperformance.measureUserAgentSpecificMemory() 和高解析度計時器等精確度更高的強大功能。

更新

  • 2022 年 6 月 21 日:啟用跨來源隔離功能時,也需要注意 worker 指令碼。新增一些說明。
  • 2021 年 8 月 5 日:JS Self-Profiling API 曾被提及為需要跨來源隔離的 API 之一,但考量近期的方向變更,我們已將其移除。
  • 2021 年 5 月 6 日:根據意見回饋和回報的問題,我們決定調整在 Chrome M92 中限制非跨來源隔離網站使用 SharedArrayBuffer 的時間表。
  • 2021 年 4 月 16 日:新增有關新版 COEP 無憑證模式COPA 同源允許彈出式視窗的鬆散條件的說明,以便跨來源隔離。
  • 2021 年 3 月 5 日:移除 SharedArrayBufferperformance.measureUserAgentSpecificMemory() 和偵錯功能的限制,這些功能現在已在 Chrome 89 中全面啟用。新增即將推出的功能 performance.now()performance.timeOrigin,可提供更高的精確度。
  • 2021 年 2 月 19 日:新增有關功能政策 allow="cross-origin-isolated" 和開發人員工具偵錯功能的附註。
  • 2020 年 10 月 15 日self.crossOriginIsolated 可在 Chrome 87 以上版本使用。 因此,當 self.crossOriginIsolated 傳回 true 時,document.domain 就會變得不可變動。performance.measureUserAgentSpecificMemory() 來源試用已結束,並預設在 Chrome 89 中啟用。自 Chrome 88 起,Android Chrome 上的共用陣列緩衝區將可供使用。

部分網路 API 會提高 Spectre 等側通道攻擊的風險。為降低這類風險,瀏覽器會提供稱為跨來源隔離的選擇加入式隔離環境。有了跨來源隔離狀態,網頁就能使用特權功能,包括:

API 說明
SharedArrayBuffer 這是 WebAssembly 執行緒的必要條件。這項功能可在 Android Chrome 88 以上版本使用。電腦版目前預設會透過 網站隔離功能啟用,但需要跨來源隔離狀態,且 在 Chrome 92 版中預設會停用
performance.measureUserAgentSpecificMemory() 適用於 Chrome 89 以上版本。
performance.now()performance.timeOrigin 目前許多瀏覽器都支援這項功能,但解析度上限為 100 微秒。使用跨來源隔離功能時,解析度可達 5 微秒或更高。
跨來源隔離狀態下可用的功能。

跨來源隔離狀態也會防止修改 document.domain。(能夠變更 document.domain 可讓同網站文件之間進行通訊,並被視為相同來源政策中的漏洞)。

如要啟用跨來源隔離狀態,您必須在主要文件中傳送下列 HTTP 標頭:

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

這些標頭會指示瀏覽器封鎖未選擇由跨來源文件載入的資源或 iframe,並防止跨來源視窗直接與您的文件互動。這也表示跨來源載入的資源需要選擇加入。

您可以檢查 self.crossOriginIsolated,判斷網頁是否處於跨來源隔離狀態。

本文將說明如何使用這些新標頭。在後續文章中,我會提供更多背景資訊和相關說明。

部署 COOP 和 COEP,讓網站隔離跨來源

整合 COOP 和 COEP

1. 在頂層文件中設定 Cross-Origin-Opener-Policy: same-origin 標頭

在頂層文件中啟用 COOP: same-origin 後,具有相同來源的視窗和從文件開啟的視窗,都會設有個別的瀏覽內容群組,除非這些視窗位於相同來源且具有相同的 COOP 設定。因此,系統會強制執行已開啟視窗的隔離作業,並停用兩個視窗之間的相互通訊。

瀏覽內容群組是一組可互相參照的視窗。例如,透過 <iframe> 嵌入的頂層文件及其子文件。如果網站 (https://a.example) 開啟彈出式視窗 (https://b.example),開啟者視窗和彈出式視窗會共用相同的瀏覽內容,因此可透過 window.opener 等 DOM API 相互存取。

瀏覽情境群組

您可以透過開發人員工具,查看視窗開啟者和其開啟者是否位於不同的瀏覽內容群組。

2. 確認資源已啟用 CORP 或 CORS

請確認網頁中的所有資源皆使用 CORP 或 CORS HTTP 標頭載入。這是第四步驟 (啟用 COEP)的必要步驟。

請根據資源的性質採取以下行動:

  • 如果預期資源只從相同來源載入,請設定 Cross-Origin-Resource-Policy: same-origin 標頭。
  • 如果資源只會從同一個網站載入,但跨來源,請設定 Cross-Origin-Resource-Policy: same-site 標頭。
  • 如果資源是從您控管的跨來源載入,請盡可能設定 Cross-Origin-Resource-Policy: cross-origin 標頭。
  • 針對您無法控制的跨來源資源:
    • 如果資源是透過 CORS 提供,請在載入 HTML 標記中使用 crossorigin 屬性。例如 <img src="***" crossorigin>
    • 請資源擁有者支援 CORS 或 CORP。
  • 針對 iframe,請遵循上述相同原則,並設定 Cross-Origin-Resource-Policy: cross-origin (或 same-sitesame-origin,視情況而定)。
  • 使用 WebWorker 載入的指令碼必須從相同來源提供,因此您不需要 CORP 或 CORS 標頭。
  • 如果是透過 COEP: require-corp 提供的文件或 worker,未透過 CORS 載入的跨來源子資源必須設定 Cross-Origin-Resource-Policy: cross-origin 標頭,才能選擇嵌入。例如,這適用於 <script>importScripts<link><video><iframe> 等。

3. 使用 COEP Report-Only HTTP 標頭評估嵌入式資源

在完全啟用 COEP 之前,您可以使用 Cross-Origin-Embedder-Policy-Report-Only 標頭進行模擬測試,檢查政策是否確實運作。您會收到報表,但不會封鎖內嵌內容。

將此做法遞迴套用至「所有」文件,包括頂層文件、iframe 和 worker 指令碼。如要瞭解僅供報表使用的 HTTP 標頭,請參閱「使用報表 API 觀察問題」一文。

4. 啟用 COEP

確認一切運作正常,且所有資源都能順利載入後,請將 Cross-Origin-Embedder-Policy-Report-Only 標頭切換為 Cross-Origin-Embedder-Policy 標頭,並將相同值套用至所有文件,包括透過 iframe 和 worker 指令碼嵌入的文件。

使用 self.crossOriginIsolated 判斷隔離作業是否成功

如果網頁處於跨來源隔離狀態,且所有資源和視窗都在相同的瀏覽內容群組中隔離,self.crossOriginIsolated 資源就會傳回 true。您可以使用這個 API 判斷是否已成功隔離瀏覽內容群組,並取得 performance.measureUserAgentSpecificMemory() 等強大功能的存取權。

使用 Chrome 開發人員工具偵錯

對於在畫面上算繪的資源 (例如圖片),您可以輕鬆偵測 COEP 問題,因為系統會封鎖要求,且網頁會指出缺少圖片。不過,如果資源並非一定會產生視覺影響 (例如指令碼或樣式),則可能會發生 COEP 問題而未被發現的情況。請使用開發人員工具「網路」面板。如果 COEP 有問題,您應該會在「狀態」欄中看到 (blocked:NotSameOriginAfterDefaultedToSameOriginByCoep)

網路面板的「狀態」欄中顯示 COEP 問題。

接著按一下項目即可查看詳細資料。

在「Network」面板中按一下網路資源後,就會在「Headers」分頁中顯示 COEP 問題的詳細資料。

您也可以透過「Application」面板判斷 iframe 和彈出式視窗的狀態。前往左側的「Frames」部分,展開「top」,即可查看資源結構的細目。

您可以查看 iframe 的狀態,例如 SharedArrayBuffer 是否可用等。

Chrome 開發人員工具 iframe 檢查器

您也可以查看彈出式視窗的狀態,例如是否隔離跨來源。

Chrome 開發人員工具彈出式視窗檢查器

使用 Reporting API 觀察問題

Reporting API 是另一種可用來偵測各種問題的機制。您可以設定 Reporting API,在 COEP 阻止資源載入或 COOP 隔離彈出式視窗時,指示使用者的瀏覽器傳送報表。自 69 版起,Chrome 就支援 Reporting API,可用於各種用途,包括 COEP 和 COOP。

如要瞭解如何設定報表 API 並設定伺服器以接收報表,請參閱「使用報表 API」一文。

COEP 報告範例

跨來源資源遭到封鎖時,COEP 報告酬載的範例如下所示:

[{
  "age": 25101,
  "body": {
    "blocked-url": "https://third-party-test.glitch.me/check.svg?",
    "blockedURL": "https://third-party-test.glitch.me/check.svg?",
    "destination": "image",
    "disposition": "enforce",
    "type": "corp"
  },
  "type": "coep",
  "url": "https://cross-origin-isolation.glitch.me/?coep=require-corp&coop=same-origin&",
  "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4249.0 Safari/537.36"
}]

COOP 報表範例

在彈出式視窗開啟時,COOP 報告酬載的範例如下:

[{
  "age": 7,
  "body": {
    "disposition": "enforce",
    "effectivePolicy": "same-origin",
    "nextResponseURL": "https://third-party-test.glitch.me/popup?report-only&coop=same-origin&",
    "type": "navigation-from-response"
  },
  "type": "coop",
  "url": "https://cross-origin-isolation.glitch.me/coop?coop=same-origin&",
  "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4246.0 Safari/537.36"
}]

當不同的瀏覽內容群組嘗試彼此存取 (僅限於「僅回報」模式) 時,COOP 也會傳送報表。舉例來說,嘗試 postMessage() 時的報表會像這樣:

[{
  "age": 51785,
  "body": {
    "columnNumber": 18,
    "disposition": "reporting",
    "effectivePolicy": "same-origin",
    "lineNumber": 83,
    "property": "postMessage",
    "sourceFile": "https://cross-origin-isolation.glitch.me/popup.js",
    "type": "access-from-coop-page-to-openee"
  },
  "type": "coop",
  "url": "https://cross-origin-isolation.glitch.me/coop?report-only&coop=same-origin&",
  "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4246.0 Safari/537.36"
},
{
  "age": 51785,
  "body": {
    "disposition": "reporting",
    "effectivePolicy": "same-origin",
    "property": "postMessage",
    "type": "access-to-coop-page-from-openee"
  },
  "type": "coop",
  "url": "https://cross-origin-isolation.glitch.me/coop?report-only&coop=same-origin&",
  "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4246.0 Safari/537.36"
}]

結論

使用 COOP 和 COEP HTTP 標頭的組合,將網頁選為特殊的跨來源隔離狀態。您可以檢查 self.crossOriginIsolated,判斷網頁是否處於跨來源隔離狀態。

我們會在這個跨來源隔離狀態推出新功能,並進一步改善 DevTools 的 COOP 和 COEP 時,持續更新這篇文章。

資源