COOP と COEP を使用してウェブサイトを「クロスオリジン分離」を実現

COOP と COEP を使用してクロスオリジンの隔離環境をセットアップし、SharedArrayBufferperformance.measureUserAgentSpecificMemory()、高精度のタイマーなどの強力な機能を精度の高い方法で有効にします。

更新

  • 2022 年 6 月 21 日: ワーカー スクリプトも、クロスオリジン分離が有効になっている場合に注意が必要です。説明を追加しました。
  • 2021 年 8 月 5 日: クロスオリジン分離を必要とする API の一つとして JS Self-Profiling API が言及されましたが、最近の方向変更を反映して削除されました。
  • 2021 年 5 月 6 日: フィードバックと報告された問題に基づき、Chrome M92 でクロスオリジンのない分離サイトでの SharedArrayBuffer の使用を制限するスケジュールを調整しました。
  • 2021 年 4 月 16 日: 新しい COEP 認証情報なしモードCOOP same-origin-allow-popups をクロスオリジン分離の緩和条件にすることに関する注記を追加しました。
  • 2021 年 3 月 5 日: SharedArrayBufferperformance.measureUserAgentSpecificMemory()、デバッグ機能の制限が削除され、Chrome 89 で完全に有効になりました。今後リリースされる機能(performance.now()performance.timeOrigin)は精度が向上する予定です。
  • 2021 年 2 月 19 日: 機能ポリシー allow="cross-origin-isolated" と DevTools のデバッグ機能に関する注記を追加しました。
  • 2020 年 10 月 15 日: self.crossOriginIsolated が Chrome 87 から利用できるようになりました。 したがって、self.crossOriginIsolatedtrue を返す場合、document.domain は変更できません。performance.measureUserAgentSpecificMemory() のオリジン トライアルが終了し、Chrome 89 ではデフォルトで有効になっています。Android Chrome の共有配列バッファは、Chrome 88 以降で利用可能になります。

一部のウェブ 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 を介して相互にアクセス可能です。

ブラウジング コンテキスト グループ

ウィンドウ オープナーとウィンドウ オープナーが、DevTools とは別のブラウジング コンテキスト グループにあるかどうかを確認できます。

2. リソースで CORP または CORS が有効になっていることを確認してください

ページ内のすべてのリソースが CORP または CORS の HTTP ヘッダーで読み込まれるようにします。この手順は、COEP を有効にするステップ 4 で必要です。

リソースの性質に応じて、以下を行う必要があります。

  • リソースを同じオリジンからのみ読み込むことが想定される場合は、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 で提供されるドキュメントまたはワーカーの場合、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、ワーカー スクリプトを含むすべてのドキュメントにこれを再帰的に適用します。Report-Only HTTP ヘッダーについては、Reporting API を使用して問題を確認するをご覧ください。

4. COEP を有効にする

すべてが機能し、すべてのリソースが正常に読み込めることを確認したら、Cross-Origin-Embedder-Policy-Report-Only ヘッダーを Cross-Origin-Embedder-Policy ヘッダーに切り替えます。このヘッダーには、iframe やワーカー スクリプトを介して埋め込まれたドキュメントを含むすべてのドキュメントに同じ値を指定します。

self.crossOriginIsolated で分離が成功したかどうかを確認する

ウェブページがクロスオリジン分離状態で、すべてのリソースとウィンドウが同じブラウジング コンテキスト グループ内で分離されている場合、self.crossOriginIsolated プロパティは true を返します。この API を使用すると、ブラウジング コンテキスト グループが正常に分離され、performance.measureUserAgentSpecificMemory() などの強力な機能を利用できるようになったかどうかを判断できます。

Chrome DevTools を使用して問題をデバッグする

画面上にレンダリングされるリソース(画像など)の場合、リクエストがブロックされ、ページで画像がないことを示すため、COEP の問題を簡単に検出できます。ただし、スクリプトやスタイルなど、必ずしも視覚的に影響を与えないリソースの場合、COEP の問題は気づかない可能性があります。その場合は、DevTools の [Network] パネルを使用します。COEP に問題がある場合は、[ステータス] 列に (blocked:NotSameOriginAfterDefaultedToSameOriginByCoep) が表示されます。

[Network] パネルの [Status] 列に表示される COEP の問題。

エントリをクリックすると、詳細が表示されます。

[Network] パネルでネットワーク リソースをクリックすると、COEP の問題の詳細が [Headers] タブに表示されます。

[Application] パネルで iframe とポップアップ ウィンドウのステータスを確認することもできます。左側の [Frames] セクションに移動して [top] を開くと、リソース構造の内訳を確認できます。

SharedArrayBuffer が使用可能かどうかなど、iframe のステータスを確認できます。

Chrome DevTools iframe インスペクタ

クロスオリジン分離かどうかなど、ポップアップ ウィンドウのステータスを確認することもできます。

Chrome DevTools ポップアップ ウィンドウ インスペクタ

Reporting API を使用して問題を確認する

Reporting API を使用すると、さまざまな問題を検出できます。COEP がリソースの読み込みをブロックしたときや、COOP がポップアップ ウィンドウを分離するたびに、ユーザーのブラウザにレポートを送信するように、Reporting API を構成できます。Chrome は、バージョン 69 以降、COEP や COOP などのさまざまな用途向けに Reporting API をサポートしています。

Reporting API を構成し、レポートを受信するサーバーをセットアップする方法については、Reporting 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"
}]

Co-op レポートの例

ポップアップ ウィンドウを分離して開いた場合の 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 HTTP ヘッダーと COEP HTTP ヘッダーを組み合わせて使用し、ウェブページを特別なクロスオリジン分離状態にオプトインします。self.crossOriginIsolated を調べると、ウェブページがクロスオリジン分離状態になっているかどうかを判断できます。

このクロスオリジン分離状態で新機能が利用可能になった際には、この投稿を随時更新していきます。また、CoOP と COEP に関する DevTools のさらなる改善についてもお伝えしていきます。

リソース