優れた機能のために「クロスオリジン分離」が必要な理由

SharedArrayBufferperformance.measureUserAgentSpecificMemory()、高解像度タイマーなどの優れた機能を高い精度で使用するためにクロスオリジン分離が必要な理由について説明します。

はじめに

COOP と COEP を使用してウェブサイトを「クロスオリジン分離」にするで、COOP と COEP を使用して「クロスオリジン分離」状態に移行する方法について説明しました。この関連記事では、ブラウザで強力な機能を有効にするためにクロスオリジン分離が必要な理由について説明します。

背景

ウェブは同一オリジン ポリシーに基づいて構築されています。同一オリジン ポリシーとは、ドキュメントやスクリプトが別のオリジンのリソースとやり取りする方法を制限するセキュリティ機能です。この原則により、ウェブサイトがクロスオリジン リソースにアクセスする方法は制限されます。たとえば、https://a.example からのドキュメントは、https://b.example でホストされているデータにはアクセスできません。

ただし、これまでは同一オリジン ポリシーにいくつかの例外がありました。どのウェブサイトでも、次のことができます。

  • クロスオリジンの iframe を埋め込む
  • 画像やスクリプトなどのクロスオリジン リソースを含める
  • DOM 参照を使用してクロスオリジンのポップアップ ウィンドウを開く

ウェブをゼロから設計できれば、このような例外は存在しません。残念ながら、ウェブ コミュニティが厳格な同一オリジン ポリシーの主なメリットに気づく頃には、ウェブはすでにこうした例外に依存していました。

このようなゆるい同一オリジン ポリシーのセキュリティ副作用には、2 つの方法でパッチが適用されました。1 つの方法は、クロスオリジン リソース シェアリング(CORS)という新しいプロトコルを導入することでした。CORS の目的は、サーバーが特定のオリジンとリソースを共有できるようにすることです。もう 1 つは、下位互換性を保ちながら、クロスオリジン リソースへのスクリプトの直接アクセスを暗黙的に削除する方法です。このようなクロスオリジン リソースは「不透明」リソースと呼ばれます。たとえば、CORS が画像に適用されていない限り、CanvasRenderingContext2D を使用してクロスオリジン画像のピクセルを操作するのはそのためです。

これらのポリシーに関する決定はすべて、ブラウジング コンテキスト グループ内で行われます。

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

長い間、ブラウザの安全性を確保するには CORS と不透明なリソースの組み合わせで十分でした。場合によっては、エッジケース(JSON の脆弱性など)が発見され、パッチの適用が必要になりましたが、全体としてはクロスオリジン リソースの RAW バイトへの直接読み取りアクセスを許可しないという原則は成功しました。

これはすべて、Spectre によって変更されました。Spectre は、コードと同じブラウジング コンテキスト グループに読み込まれたすべてのデータを読み取れるようにします。攻撃者は、特定のオペレーションにかかる時間を測定することで、CPU キャッシュの内容と、それを通じてプロセスのメモリの内容を推測できます。このようなタイミング攻撃は、プラットフォームに存在する粒度の細かいタイマーで可能ですが、きめ細かいタイマー(performance.now() など)と暗黙的なタイマー(SharedArrayBuffer など)のどちらでも高速化できます。evil.com にクロスオリジンの画像が埋め込まれている場合、Spectre 攻撃を使用してピクセルデータを読み取ることができるため、「不透明度」に依存する保護が無効になります。

スペクター

理想的には、すべてのクロスオリジン リクエストは、リソースを所有するサーバーによって明示的に検証される必要があります。リソース所有サーバーから調査が行われない場合、データは悪意のあるアクターのブラウジング コンテキスト グループに入ることはないため、ウェブページが実行できる Spectre 攻撃には対応できません。これをクロスオリジン分離状態と呼びます。これが、COOP+COEP の役割です。

クロスオリジンの分離状態では、リクエスト元のサイトは危険性が低いとみなされます。これにより、SharedArrayBufferperformance.measureUserAgentSpecificMemory()高解像度タイマーなどの優れた機能を高い精度で利用できるようになります。これは Spectre のような攻撃に使用される可能性があります。また、document.domain を変更することもできません。

クロスオリジン エンベダー ポリシー

クロスオリジン エンベディング ポリシー(COEP)により、(CORP または CORS を使用して)ドキュメントの権限を明示的に付与していないクロスオリジン リソースをドキュメントから読み込まないようにすることができます。この機能を使用すると、このようなリソースをドキュメントで読み込めないことを宣言できます。

COEP の仕組み

このポリシーを有効にするには、ドキュメントに次の 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 のコンテキストでは、COEP はリソースを読み込めるユーザーに関するリソース オーナー ポリシーを指定できます。

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 を返します。

Co-op

Cross-Origin-Opener-Policy ヘッダーは、次の 3 つの値を取ります。

Cross-Origin-Opener-Policy: same-origin

same-origin とマークされたドキュメントは、明示的に same-origin とマークされた同一オリジン ドキュメントと同じブラウジング コンテキスト グループを共有できます。

Co-op

Cross-Origin-Opener-Policy: same-origin-allow-popups

same-origin-allow-popups を持つトップレベル ドキュメントは、COOP を設定しないポップアップ、または COOP を unsafe-none に設定して分離をオプトアウトするポップアップへの参照を保持します。

Co-op

Cross-Origin-Opener-Policy: unsafe-none

unsafe-none はデフォルトで、オープナー自体の COOP が same-origin である場合を除き、ドキュメントをオープナーのブラウズ コンテキスト グループに追加できます。

まとめ

SharedArrayBufferperformance.measureUserAgentSpecificMemory()、または高解像度タイマーのような強力な機能により高い精度で確実にアクセスできるようにするには、ドキュメントで require-corp の値を持つ COEP と same-origin の値を持つ COOP の両方を使用する必要があります。どちらも存在しない場合、ブラウザは、これらの強力な機能を安全に使用するための十分な分離を保証しません。ページの状態を判断するには、self.crossOriginIsolatedtrue を返すかどうかを確認します。

これを実装する手順については、COOP と COEP を使用してウェブサイトを「クロスオリジン分離」にするをご覧ください。

リソース