攻撃を知った上で防御する CSRF編

Blog Single

Webアプリやサイトを作成する際、悲しいことに悪意のあるユーザーからの攻撃は考慮しなければなりません。
とはいえ、実は攻撃のパターンもある程度限られています。
どのような攻撃があるかを知っておくだけで、それらの対処も施しやすくなります。

ということで、悪意のあるユーザーによる代表的な攻撃を紹介して行きます。
今回はCSRFです。

CSRFとは

「クロス・サイト・リクエスト・フォージュエリ」の略です。
簡単に説明すると、正規のルートではない外部からHTTPリクエストを送ることで、攻撃対象の機能を実行させてしまうというものです。

CSRFによる有名な事例として、10年以上前にmixiで発生した「ぼくははまちゃん!」事件があります。
これは、とあるユーザーが「ぼくははまちゃん!」というタイトルの日記をアップしていて、その本文にあるURLをクリックすると、クリックしたユーザーのページにも全く同じ「ぼくははまちゃん!」というタイトルの日記が勝手にアップされてしまう、というものでした。
その勝手にアップされた日記の本文に書いてあるURLをまた別の人がクリックしてしまう、というのを繰り返して「ぼくははまちゃん!」という日記が勝手にアップされる現象はどんどん広がっていきました。

では具体的に、CSRFはどのようにして行われるのでしょうか。

とある登録制サイトにて、ユーザーのパスワードを変更するページの処理が
メソッド:GET
URL:https://aaa/iii/uuu
パラメーター:new_pass(新しいパスワード)、new_pass_conf(確認用の新しいパスワード)
だったとして、またセッションでユーザーIDの有無を確認し、ログインしているかどうかを確認、またそのIDからユーザー情報を扱っているものとします。
セッションからログインIDを確認でき、そのIDを持つユーザーの存在が確認できた場合、そのユーザーのパスワードをnew_passに書いてある文字列に変更するとします。

ここで、ユーザーに攻撃者がメールを送ったとします。
そのメールの本文中に上記の「ぼくははまちゃん!」事件のようにURLが書いてあり、そのURLをクリックすると
メソッド:GET
URL:https://aaa/iii/uuu
パラメーター:new_pass=”hairemasen”、new_pass_conf=”hairemasen”
というリクエストが送られるとします。

仮にユーザーがログイン状態でセッションにIDを持っている状態だったり、もしくはそもそも上のメールがサイト内のメール機能で送信されているものだったら、ユーザー認証も通ってしまうのでパスワードがhairemasenに変更されてしまいます。

ではどうすべきか

上の例から分かるように、本来想定している場所以外からのリクエストによって機能が動作してしまわなければ、CSRFは失敗に終わります。

具体的に、上記の例で言えばパスワード変更確定の直前に再び認証情報を入力させる画面を挟んだり、リファラ(送信元のURL)を確認する機能を追加したりすることでCSRFを防ぐことができます。
また、もう一つ有効な手段としては“ワンタイムトークンを発行する”があります。

どういうことかというと、
1. パスワード変更フォーム表示時に一時的な暗号(ワンタイムトークン)を発行し、サーバー側で保持しておく
2. その値をフロント側でもhiddenで持たせる
3. リクエストがあったらそのhiddenの値と保持している値を照らし合わせる
4. それが合致すれば変更を通す、合致しなければ弾く

という手順を踏むことにより、外部からのリクエストを通してしまうのを防ぎます。
そして、このワンタイムトークンを作成する機能がプログラミング言語やフレームワーク内に既に用意されていたり、プラグインとして簡単に導入できたりしています。
このワンタイムトークン発行の手法を用いているサイトは多いので、なんらかのサイトのフォーム画面でGoogle ChromeのDeveloper Toolなどを使うとワンタイムトークンの存在を確認できたりして面白いかもしれません…。

まとめ

対処法のどれが適しているのかというのはサイトの特性などによって変わってきます。
たっぷり時間が使えるのであればいくつもの対策を重ねてより安全なサイトにすることも出来ますし、そこまで時間が取れなそうであれば適切な一つを選ぶ必要性が生じます。
冒頭でも述べましたが、代表的な攻撃パターンには対処法のデファクトスタンダードも存在しているので、代表的なものから覚えていきたいと思います。

技術書は勿論、本全般が好き。品揃えの良い本屋に行くとテンション上がりすぎて後で具合が悪くなる。

Other Posts: