SharedArrayBuffer
、performance.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 の役割です。
クロスオリジンの分離状態では、リクエスト元のサイトは危険性が低いとみなされます。これにより、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 のコンテキストでは、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
を返します。
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
はデフォルトで、オープナー自体の COOP が same-origin
である場合を除き、ドキュメントをオープナーのブラウズ コンテキスト グループに追加できます。
まとめ
SharedArrayBuffer
、performance.measureUserAgentSpecificMemory()
、または高解像度タイマーのような強力な機能により高い精度で確実にアクセスできるようにするには、ドキュメントで require-corp
の値を持つ COEP と same-origin
の値を持つ COOP の両方を使用する必要があります。どちらも存在しない場合、ブラウザは、これらの強力な機能を安全に使用するための十分な分離を保証しません。ページの状態を判断するには、self.crossOriginIsolated
が true
を返すかどうかを確認します。
これを実装する手順については、COOP と COEP を使用してウェブサイトを「クロスオリジン分離」にするをご覧ください。