CORB (Cross-Origin Read Blocking)
この文書はCORSの概要である。CORSは不正なクロスドメインのリソースアクセスをブラウザがブロックするアルゴリズムである。CORSはクロスオリジンのウェブページを保護し情報の漏洩リスクを減らす。ほとんどのブラウザでそのような情報は信頼できないスクリプト文脈の外に置かれる。サイト孤立化を実装するブラウザではそのような情報は信頼できないレンダラプロセスの外に置かれ、サイドチャネル攻撃にも有効になる。
問題点
同一オリジンポリシーは一般的に1つのオリジンが他のオリジンのネットワークリソースの読み込みを防ぐ。実際上はこのポリシーはすべてのクロスオリジン読み込みを禁止するわけではない。<img>や<script>は歴史的理由により許可される。CORSの仕組みでは選択的にオリジン感のアクセスを許可できる。
いくつかのコンテントタイプでは歴史的に許可された文脈では利用できない。1つはJSONで<img>で読み込んでもデコードエラーになるし、<script>で読み込んでもno-opかシンタックスエラーになる。ウェブページがJSONを読み込むにはfetch()やXMLHttpRequestを使う。このようなときにCORSが働く。
CORBによってどのような攻撃から守れるのか?
以下のような攻撃ベクトルを緩和する。
- クロスサイトスクリプト包含(XSSI)
- XSSIは<script>タグを攻撃者サイトに埋め込みJavascriptでないものをそれとして動かして副作用を発生させるものである。この攻撃の初期の実例は2006に発見された。Javascript配列コンストラクタを上書きしJSONのリストが<script src="https://example.com/secret.json">と解釈される。配列コンストラクタ攻撃は現在では修正されているが同じようなものがその後の10年間で見つかっては修正されてきた。実例としてこのスライドを参照。
- CORBはこのクラスの攻撃を防ぐ。CORBで防御されたリソースはクロスサイトの<script>をブロックする。
- CORBはXSRFトークンやJSONセキュリティプリフィクスがないときに特に効果を発揮する。
- 投機的サイドチャネル攻撃(いわゆるSpectre)
- 例えば攻撃者は<img src="https://example.com/secret.json">を使って攻撃者のサイトでユーザーにアクセスさせ機密情報を取得しようとする。
- CORBはこの攻撃をサイト孤立化と並行して防ぐ。JSONリソースをホストされているクロスサイトのメモリ上に展開して防ぐ。
CORBはどのようにレスポンスをブロックするか?
CORBがレスポンスをブロックする必要があるときは、レスポンスは以下のように修正される。
- レスポンスボディは空のボディになる。
- レスポンスヘッダは削除される。
[lukasza@chromium.org] Chromium currently retains Access-Control-* headers (this helps generate better error messages for CORS).
投機的サイドチャネル攻撃を有効に防御するためには、CORBブロックはレスポンスがクロスオリジンリクエストを開始したプロセスに到達する前にブロックする必要がある。言い換えるとCORBブロックはCORB防御されたレスポンスがクロスオリジンをホストするプロセスのメモリ上に存在しないことが必要である(一時的であれ短期間であれ)。これはフィルターされたレスポンス(すなわちCORSフィルターレスポンスや不透明フィルターレスポンス)とも異なる。これらはデータを制限するだけであり全データは内部レスポンスに保存されレンダラプロセス内部に存在する。
CORBのデモページが利用できる。
どんな種類のレクエストがCORB適格なのか?
以下の種類のリクエストはCORB免除である。
- ナビゲーションリクエストまたはリクエストの目的地が「オブジェクト」や「組み込み」の場合。クロスオリジンの<iframe>や<object>や<embed>は分離されたセキュリティ文脈が作成されるので情報漏えいのリスクは軽減される。この分離された文脈により悪意のあるページはそれを自分の文脈で副作用を及ぼす(XSSIやスタイルタグなど)よりも内容の推測が困難になる。
[lukasza@chromium.org] TODO: エッジのVMベースの孤立化の仕組みを理解すること。(もしあるオリジンが特定のレンダラで制限されたら、CORBの効率が増加する)。
- ダウンロードリクエスト(開始者は「ダウンロード」のリクエスト)。このケースの場合はレスポンスはディスクに保存される(クロスオリジン文脈で共有されない)のでCORB防御からは利益を得られない。
[lukasza@chromium.org] 自分の知る限り、Chromeではダウンロードリクエストのレスポンスは決してレンダラプロセスのメモリを通過しない。他のブラウザではどうなっているかはよくわからない。
他のすべてのCORB適格であるリクエストは以下
- XHRとfetch()
- ping, navigator.sendBeacon()
- <link ref="prefetch" ...>
- 以下のリクエスト目的地のリクエスト
- 「image」リクエスト。<img>タグや/favicon.icoやSVGの<image>やCSSのbackground-imageなど
- スクリプト目的地。<script>、importScripts()、navigator.serviceWorker.register()、audioWorklet.addModule()など
- 「audio」、「video」、「track」
- 「font」
- 「style」
- CSPレポートやNELレポートなどの「report」リクエスト
CORBの本質はあるリソースが上記の文脈の中で適当かどうかということである。CORSエラーやシンタクス・デコードエラー、あるいは見ることができない結果の生じるようなリクエストはCORBで読み込みの内容を変更することなくクロスオリジン読み込みのブロックが可能であるべきである。CORBよりも前に、詳細情報はすでにクロスオリジンエラーで制限されている。このように観察できるエラー結果はすでに制限されているのでブロックしていても保たれる。
どのタイプのコンテントがCORBに防御されるか?
以下で述べるように次のタイプのコンテントはCORB防御である。
- JSON
- HTML
- XML
これらは以下のセクションで論じる。