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