第8章 マッシュアップ
クライアントサイドマッシュアップ: #3 リクエスト強要攻撃による善意のAPIへの侵害
シナリオ4は、悪意のサイトのコンテンツにブラウザが操られ、ユーザの意思に反して善意のAPIへの攻撃が起こるというものである。このシナリオで考えられる攻撃には「リクエスト強要攻撃」がある。本節では、クライアントサイドマッシュアップの状況におけるリクエスト強要攻撃について論じる。
「リクエスト強要攻撃」
リクエスト強要攻撃は、罠のコンテンツを用いてブラウザを誘導し、ユーザの意思に反したHTTPリクエストを善意のWebサーバへ送信させる攻撃である。ユーザ本人の望まない「更新系」のトランザクションが投入され、被害が生じる。
これまで注意深いWebアプリケーション開発者の間では、サーバにおける「更新系」の処理について「リクエスト強要攻撃」が警戒され、対策がとられてきた。対策が「更新系」に限定されていたのは、従来型のWebアプリケーションでは「参照系」のトランザクションが投入されても攻撃者がその処理結果を入手することが困難であり、あまり実害が無かったからである。
しかし、クライアントサイドマッシュアップにおいては「非同期の他源泉リクエスト」という手法が多用され、その状況においては「更新系」の処理のみならず、「参照系」の処理についても「リクエスト強要攻撃」への警戒と対策が必要になってきた。
「非同期の他源泉リクエスト」
本稿で「非同期の他源泉リクエスト」と呼ぶのは次のような動作を実現するプログラミング手法のことである──
ブラウザ上の JavaScript コード内からその JavaScript コードの出身サーバ ("源泉") とは異なる Web サーバ ("他源泉") へ HTTP リクエストを送ってレスポンスを受け取り、その後も元の JavaScript コードが動作を継続する動作
「非同期の他源泉リクエスト」複数の方法
「非同期の他源泉リクエスト」の実現方法には、これまで次の5つが知られている。

- JSONP ── JSON 形式の文字列データを引数にとる関数呼び出しの形態の JavaScript ソースコードを、動的に <script> タグを生成して他源泉からロードする方法
- iframeコール ── 親・子・孫三代の iframe 構造を用い、他源泉へのリクエスト送信 (子) と源泉間のデータ受け渡し (孫) を分担して行う方法
- iframe + postMessage ── HTML5 の postMessage を用いて iframe内外のデータ受け渡しを行う方法
- Webワーカ + importScripts ── HTML5 の Webワーカ と、Webワーカ に備わる importScripts とを用いて JavaScript コードを他源泉からロードする方法
- XMLHttpRequest level 2 ── 他源泉へリクエストを出せるよう拡張された XMLHttpRequest 組み込みオブジェクトを用いる方法 (Microsoft Internet Explorer においては名前の異なる XDomainRequest という組み込みオブジェクトを用いる)
他源泉におけるリクエスト強要攻撃
5種類の「非同期の他源泉リクエスト」方法のそれぞれについて、サーバの「参照系」処理に対する「リクエスト強要攻撃」が情報漏えいを引き起こす模様を想定してみる。
(1) リクエスト強要攻撃―JSONP
JSONPにおけるリクエスト強要攻撃は下記の図のように行われる。

善意のサーバ (サーバB) のセッションが Cookie で維持されている状況下で、悪意のサーバのコンテンツが正常系と同様の JSONP 手法を用い、サーバBからデータを不正に入手する。
ここでは次を仮定している。
- ブラウザがサーバBの有効なセッションIDのCookieをもっている
(2) リクエスト強要攻撃―iframeコール
iframeコールにおけるリクエスト強要攻撃は下記の図のように行われる。

善意のサーバ (サーバB) のセッションが Cookie で維持されている状況下で、悪意のサーバのコンテンツが正常系と同様の iframe コール手法を用い、サーバBからデータを不正に入手する。
ここでは次を仮定している。
- ブラウザが、サーバBの有効なセッションIDのCookieをもっている(XHR 1 でも Cookie が飛ぶ)
- サーバBのiframeコンテンツに対して孫iframeにロードさせるコンテンツのURIをパラメタで指定できるが、その妥当性に関するサーバBにおける検査が甘い
(3) リクエスト強要攻撃―iframe+postMessage
iframe+postMessageにおけるリクエスト強要攻撃は下記の図のように行われる。

善意のサーバ (サーバB) のセッションが Cookie で維持されている状況下で、iframe 子要素が親要素へ postMessage でデータを受け渡してくるのをそのまま受け取り、悪意のサーバがデータを不正に入手する。
ここでは次を仮定している。
- ブラウザが、サーバBの有効なセッションIDのCookieをもっている(XHR 1 でも Cookie が飛ぶ)
(4) リクエスト強要攻撃―ワーカ+importScripts
ワーカ+importScripts におけるリクエスト強要攻撃は下記の図のように行われる。

善意のサーバ (サーバB) のセッションが Cookie で維持されている状況下で、悪意のサーバのコンテンツが importScripts を使用して、サーバBからデータを不正に入手する。
ここでは次を仮定している。
- ブラウザが、サーバBの有効なセッションIDのCookieをもっている(なお、ここでは XHR 1 は使えない)
(5) リクエスト強要攻撃―XHR 2
XHR 2 におけるリクエスト強要攻撃は下記の図のように行われる。

善意のサーバ (サーバB) のセッションが Cookie で維持されている状況下で、悪意のサーバのコンテンツが XHR 2 を使用して、サーバBからデータを不正に入手する。
ここでは次を仮定している。
- ブラウザが、サーバBの有効なセッションIDのCookieをもっている
- サーバBにおけるOrigin:リクエストヘッダの検査が甘い
- 悪意のサーバに対しても、「Access-Control-Allow-Origin: リクエストしてきたサーバ」および「Access-Control-Allow-Credentials: true」のレスポンスヘッダが発行される
リクエスト強要攻撃への耐性
どのリクエスト手段もリクエスト強要攻撃の餌食になり得る。「非同期の他源泉リクエスト」の5つの方法それぞれのリクエスト強要攻撃への耐性を一覧にすると次のようになる 。

XHR 2
XMLHttpRequest level 2 (XHR 2) は「非同期の他源泉リクエスト」の5つの方法の中でも比較的強固である。XHR 2 の通信上の特徴は、HTTPリクエストおよびレスポンスの中で次のようなヘッダを用いるというものである。
- Origin: origin リクエストヘッダ
- Access-Control-Allow-Origin: origin レスポンスヘッダ
- Access-Control-Allow-Credentials: boolean レスポンスヘッダ
(これら以外にも複数種類の Access-Control-* レスポンスヘッダが存在する)
上記のヘッダ群を用いて、XHR 2 はセキュリティ確保のための振る舞いをする。主なものは次の3つである。
- JavaScript コードが要求してきたものが他源泉へのアクセスであることを自動判別し、XHR 2 はリクエストに
Origin: originリクエストヘッダを含める。ここに、origin は現在の JavaScript コードの源泉 (出身サーバ) を表す URI である。これは、リクエストが他源泉リクエストであることと、どの源泉からのリクエストであるかをサーバへ知らせるものである。
- サーバが所定の
Access-Control-Allow-Origin: originレスポンスヘッダを返して来なければ、XHR 2 はレスポンスデータを JavaScript コードへ引き渡さない
- Cookie を含むリクエストに対して、サーバが
Acess-Control-Allow-Credentials: trueレスポンスヘッダを返して来なければ、XHR 2 はレスポンスデータを JavaScript コードへ引き渡さない
- "HTTP access control" (英語)
https://developer.mozilla.org/En/HTTP_access_control
XHR 2 を用いた他源泉リクエスト
XHR 2 を用いた他源泉リクエストの通信の流れを次に示す。

XHR 2 を突破できるケース
セキュリティの配慮がある XHR 2 であっても、次のような条件が成立する場合にはリクエスト強要攻撃が成立し得る。
- クライアントから送られてきた Origin: origin リクエストヘッダに対して、サーバが必ず Access-Control-Allow-Origin: origin レスポンスヘッダを返すようになっている。かつ、
- サーバが Access-Control-Allow-Credentials: true レスポンスヘッダを発行するとともに、Cookie を用いたセッション維持を行っている。
