SharedArrayBuffer
、performance.measureUserAgentSpecificMemory()
、高解像度タイマーなどの強力な機能を高い精度で使用するために、クロスオリジン分離が必要である理由について学びます。
はじめに
COOP と COEP を使用してウェブサイトを「クロスオリジン分離」するでは、COOP と COEP を使用して「クロスオリジン分離」状態を採用する方法について説明しました。これは、ブラウザで強力な機能を有効にするためにクロスオリジン分離が必要な理由を説明するコンパニオン記事です。
背景
ウェブは、同一生成元ポリシーに基づいて構築されています。これは、ドキュメントとスクリプトが別のオリジンのリソースとやり取りする方法を制限するセキュリティ機能です。この原則により、ウェブサイトがクロスオリジン リソースにアクセスする方法が制限されます。たとえば、https://a.example
のドキュメントは https://b.example
でホストされているデータにアクセスできません。
ただし、同じオリジン ポリシーには、これまでにいくつかの例外がありました。すべてのウェブサイトは、以下のことができます。
- クロスオリジン iframe を埋め込む
- 画像やスクリプトなどのクロスオリジン リソースを含める
- DOM 参照を使用してクロスオリジン ポップアップ ウィンドウを開く
ウェブをゼロから設計できるなら、このような例外は存在しません。残念ながら、ウェブ コミュニティが厳格な同一オリジン ポリシーの主なメリットに気付いた頃には、ウェブはすでにこれらの例外を頼りにしていました。
このような緩い同一オリジン ポリシーのセキュリティ サイドエフェクトは、2 つの方法でパッチが適用されました。その 1 つは、クロスオリジン リソース シェアリング(CORS)という新しいプロトコルを導入することでした。このプロトコルの目的は、サーバーが特定のオリジンとリソースの共有を許可できるようにすることです。もう一つの方法は、下位互換性を維持しながら、クロスオリジン リソースへの直接スクリプト アクセスを暗黙的に削除することです。このようなクロスオリジン リソースは「不透明」リソースと呼ばれます。たとえば、画像に CORS が適用されていない限り、CanvasRenderingContext2D
を介してクロスオリジン画像のピクセルを操作すると失敗します。
これらのポリシーに関する決定はすべて、ブラウジング コンテキスト グループ内で行われます。
長い間、CORS と不透明リソースの組み合わせでブラウザを安全にできました。エッジケース(JSON の脆弱性など)が見つかり、パッチを適用する必要がありましたが、全体的には、クロスオリジン リソースの未加工バイトへの直接読み取りアクセスを許可しないという原則が機能しました。
Spectre により、この状況はすべて変わりました。コードと同じブラウジング コンテキスト グループに読み込まれたデータは、読み取り可能になる可能性があります。特定のオペレーションにかかる時間を測定することで、攻撃者は CPU キャッシュの内容を推測し、そこからプロセスのメモリの内容を推測できます。このようなタイミング攻撃は、プラットフォームに存在する低粒度のタイマーで可能ですが、明示的(performance.now()
など)と暗黙的(SharedArrayBuffer
など)の両方の高粒度のタイマーで高速化できます。evil.com
にクロスオリジン画像が埋め込まれている場合、Spectre 攻撃を使用してピクセルデータを読み取ることができるため、「不透明性」に依存する保護が無効になります。
理想的には、すべてのクロスオリジン リクエストは、リソースを所有するサーバーで明示的に審査する必要があります。リソース所有サーバーによって審査が行われない場合、データは不正な行為者のブラウジング コンテキスト グループに決して到達しないため、ウェブページが実行する Spectre 攻撃の範囲外になります。これをクロスオリジン分離状態と呼びます。これがまさに COOP+COEP の目的です。
クロスオリジンの分離状態では、リクエスト元のサイトは危険性が低いと見なされます。これにより、SharedArrayBuffer
、performance.measureUserAgentSpecificMemory()
、高解像度タイマーなどの強力な機能が利用可能になり、精度が向上します。これらの機能は、Spectre のような攻撃に使用される可能性があります。また、document.domain
の変更も防止されます。
クロスオリジンの埋め込みポリシー
クロスオリジン エンベディング ポリシー(COEP)は、(CORP または CORS を使用して)ドキュメントの権限が明示的に付与されていないクロスオリジン リソースをドキュメントが読み込まないようにします。この機能を使用すると、ドキュメントがそのようなリソースを読み込めないことを宣言できます。
このポリシーを有効にするには、ドキュメントに次の HTTP ヘッダーを追加します。
Cross-Origin-Embedder-Policy: require-corp
COEP で許容される値は require-corp
キーワードのみです。これにより、ドキュメントが同じオリジンまたは別のオリジンから読み込み可能と明示的にマークされたリソースのみを読み込むことができるポリシーが適用されます。
リソースを別のオリジンから読み込むには、クロスオリジン リソース シェアリング(CORS)またはクロスオリジン リソース ポリシー(CORP)のいずれかをサポートする必要があります。
クロスオリジン リソース シェアリング
クロスオリジン リソースがクロスオリジン リソース シェアリング(CORS)をサポートしている場合は、crossorigin
属性を使用して、COEP によってブロックされることなくウェブページに読み込むことができます。
<img src="https://third-party.example.com/image.jpg" crossorigin>
たとえば、この画像リソースが CORS ヘッダーで提供されている場合は、crossorigin
属性を使用して、リソースを取得するリクエストで CORS モードを使用するようにします。また、CORS ヘッダーが設定されていない限り、画像が読み込まれないようにします。
同様に、fetch()
メソッドを使用してクロスオリジン データを取得することもできます。この場合、サーバーが適切な HTTP ヘッダーで応答する限り、特別な処理は必要ありません。
クロスオリジン リソース ポリシー
クロスオリジン リソース ポリシー(CORP)は、リソースが別のオリジンによって読み込まれないように保護するためのオプトインとして導入されました。COEP のコンテキストで、CORP はリソースを読み込むことができるユーザーに関するリソース所有者のポリシーを指定できます。
Cross-Origin-Resource-Policy
ヘッダーには、次の 3 つの値を指定できます。
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 仕様に追加されました)。
クロスオリジンのオープナー ポリシー
クロスオリジン オープナー ポリシー(COOP)を使用すると、トップレベル ウィンドウを他のドキュメントから分離し、異なるブラウジング コンテキスト グループに配置して、トップレベル ウィンドウを直接操作できないようにすることができます。たとえば、COOP を含むドキュメントがポップアップを開くと、その window.opener
プロパティは null
になります。また、オープンしたアプリの参照の .closed
プロパティは true
を返します。
Cross-Origin-Opener-Policy
ヘッダーには、次の 3 つの値を指定できます。
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()
、高解像度タイマーなどの強力な機能に高い精度でアクセスできるようにするには、ドキュメントで require-corp
の値の COEP と same-origin
の値の COOP の両方を使用する必要があります。どちらもない場合、ブラウザはこれらの強力な機能を安全に有効にするための十分な分離を保証できません。ページの状況は、self.crossOriginIsolated
が true
を返すかどうかで判断できます。
実装手順については、COOP と COEP を使用してウェブサイトを「クロスオリジン分離」するをご覧ください。