エンジニアリング部システムソリューション課のひよっこエンジニアKと申します。エンジニアになってまだ2ヶ月強の私は、課題や仕事に取り組む中でわからないことにぶち当たることが多いです。この記事は、わからないところについて調べた結果などをまとめています。
今回のテーマは、CSRF対策についてです。今回課題をやっていて苦戦したところ等を主に書いていきます。まだまだ調べが足りない点も多いので、随時更新予定です。
そもそもCSRF(クロスサイト・リクエストフォージェリ)とは何なのか?
Webアプリケーションにはログインした利用者のアカウントにより、取り消せない重要な処理(利用者のクレジットカードでの決済や、利用者の口座からの送金、メール送信、パスワードやメールアドレスの変更など)が実行できるものがあります。『安全なWebアプリケーションの作り方(第2版)』によると、CSRF攻撃は利用者のブラウザから罠サイトを閲覧しただけで、勝手にこのような重要な処理を実行させる攻撃です。
よくある被害として、twitterの利用者がツイートされた罠リンクを踏んでしまい、自分のアカウントで勝手にスパムのツイートがされるようになる、というものがあります。それ以外にも、自分のショッピングサイトのアカウントで勝手に物が購入されていたり、勝手にパスワードやメールアドレスが変更されていたりというような被害が起こる可能性があります。
CSRFの典型的な攻撃手法
CSRF対策をするためには、攻撃手法を理解しておく必要があります。ここでは図で具体的に見てみましょう。
①利用者が攻撃対象のサービスにログインする
実はここがCSRF攻撃の鍵です。利用者がサービスにログイン状態でないとCSRF攻撃はできません。
②攻撃者が罠を用意する
攻撃者は罠のサイトやリンクを用意します。そこには攻撃用のスクリプトが仕込んであり、利用者のログイン情報(セッションIDなど)が入ればリクエストが送信できる状態になっています。
③利用者が罠を閲覧する
利用者が罠サイトを閲覧したり罠URLをクリックすることで、攻撃用スクリプトにセッションIDなどが入ります。
④攻撃対象サーバーにリクエスト送信される
セッションIDのクッキーなどがついた状態で攻撃対象サーバーにリクエストが送信されます。CSRF対策をしていないサーバーではどこのページからリクエストが送信されたかなどを区別していないので、リクエストは受け入れられます。
⑤リクエストが実行される
攻撃用スクリプトに仕込まれていたリクエスト通り、勝手にスパムのコメントを送信されていたり、パスワードが変更されていたり、知らない間に物が購入されていたりします。
CSRF対策の肝、ワンタイムトークンとは?
攻撃手法を見てみると、攻撃対象になっているサーバーではリクエスト送信元のページなどを確認していませんでした。ということは、CSRF対策ではリクエスト送信先のページで正規のページからリクエストが送信されたか確認すれば良いということになります。
そのためには、ワンタイムトークン(ランダムな文字列)を使います。ランダムな文字列にするのは他者から推測されづらいためです。固定でなくワンタイム(新しいリクエストが送られるたびに毎回生成)にしているのも攻撃者からしらみつぶしにトークンを試されるのを防ぐためです。ではワンタイムトークンの実装方法を具体的に見てみましょう。
ワンタイムトークンの実装方法
①フォーム送信前のページ(分岐)でワンタイムトークン生成
まずはフォーム送信前のページでワンタイムトークンを生成します。phpなら、openssl_random_pseudo_bytes関数などを使うと良いと思います。ここで生成したワンタイムトークンをセッションに格納します。
②フォーム送信ページにhiddenで生成したトークンを埋め込む
フォーム送信用のhtmlページにinputタグのhidden要素で先程生成したトークンを埋め込みます。これでフォーム送信した際に埋め込まれたトークンの値も送信されます。
③リクエスト送信先でセッションに格納されたトークンとリクエストとして送られてきたトークンが一致するか確認
リクエスト送信先のページ(送信元と同じならリクエスト送信された分岐)でセッションに格納されたトークンと送られてきたトークンが一致するか確認します。トークンがない場合や、セッションの値と一致しなかった場合はリクエストを受け付けないようにしておきます。
ワンタイムトークン以外のCSRF対策
ワンタイムトークン以外のCSRF対策として、リクエストを送信する前に再度ログイン認証させるという方法や、パズルや英数字、ランダムな画像について答えを入力させる方法もあります。パスワード変更するとき、現在のパスワードの入力が求められることも多いと思いますが、これもCSRF対策なのです。また、パズルや英数字、ランダムな画像の答え入力もWebアプリケーションを利用する上で出会ったことがあると思いますが、これはワンタイムトークンと考えは一緒で、ランダムにすることで他者から推測されづらいようにしています。
今回のまとめ
①CSRF(クロスサイト・リクエストフォージェリ)攻撃とは、利用者が攻撃対象のサービスにログインした状態で罠を閲覧することで、利用者のログイン情報を利用されて勝手に攻撃用スクリプトのリクエストを送信されてしまう攻撃
②HTTP通信ではどこからリクエストが送られてきたか確認していないので、アプリケーション側でリクエスト送信元を確認しておく必要がある
③リクエスト送信元を確認する方法として、ワンタイムトークンを利用する方法や再度ログイン認証を行う方法、ランダムな画像などの答えを入力させる方法がある
④ワンタイムトークンを実装するときは、フォーム送信前のページ(分岐)でトークンをセッションに格納しておくことが必要
参考サイト:
CSRF(クロスサイトリクエストフォージェリ:リクエスト強要)って一体何? どう対策すればいいの?
CSRF(クロスサイト・リクエスト・フォージェリ)とは?その仕組みと対策方法について
サイトを安全に!PHPでcsrf対策を行う方法【初心者向け】
参考図書:
『安全なWebアプリケーションの作り方(第2版)』(徳丸浩著) p.175-196