はじめに
今回は、CSRFの対策を行っているサイトに対して、OWASP ZAPを利用して脆弱性診断を行います。
そのための設定や、実際に攻撃を行い動作確認を行いました。
OWASP ZAPのインストール方法や、基本的な使い方は以下にまとめましたのでご覧ください。
脆弱性の危険性を試した記事を以前まとめましたので、あわせてご覧ください。
Mac版のOWASP ZAPについては以下の記事をご覧ください。
本記事ではWindows版で解説していますが、使い方はMac版でも同様です。
他にも私のブログで、ツールについて解説している記事がありますのでご覧ください。
CSRFとは
CSRFとはクロスサイトリクエストフォージェリの略で、脆弱性の一種です。
例えば、利用者が悪意のあるサイトにアクセスし、外部サイトに意図しないリクエストを送信されてしまう場合があります。
利用者が掲示板に、意図しない投稿をさせられた事件がありました。
サイト側がCSRFの対策が行われていないためでした。
(「ぼくはまちちゃん」 騒動など)
CSRFの詳細については、IPAのサイトをご覧ください。
仕組みなどが理解できると思います。

この対策が行われているサイトに対しては、都度生成されるトークンを利用し正規の送信か判断しており、OWASP ZAPで脆弱性診断を行う場合、設定を行う必要があります。
OWASP ZAPの設定
対象サイト
今回は、Laravelで簡単なフォームを作成しました。
以下の記事で作成したフォームを利用します。
テンプレートファイルにフォームを用意します。
<html>
<body>
<form method="POST" action="{{ route('login-result') }}">
@csrf
<input type="text" name="id" placeholder="ID"><br>
<input type="text" name="password" placeholder="PASSWORD"><br>
<input type="submit" value="ログイン">
</form>
</body>
</html>
実際にブラウザでアクセスして、HTMLタグを確認します。
Laravelは自動でCSRFのトークンをフォームに挿入します。(_tokenという隠しパラメータ)
<html>
<body>
<form method="POST" action="http://192.168.0.14:8000/login">
<input type="hidden" name="_token" value="ZGpBv7i2MakcH82xqR9Nz5d6HPkO1NWjOOIpv6yl">
<input type="text" name="login_id" placeholder="ID"><br>
<input type="text" name="password" placeholder="PASSWORD"><br>
<input type="submit" value="ログイン">
</form>
</body>
</html>
画面を開いてSubmitボタンをクリックすれば、問題なくリクエストを送信できます。

もし不正なトークンを送信した場合は、LaravelのCSRF対策に弾かれ、レスポンスコード:419が返却されます。

設定
OWASP ZAPのオプションを開きます。

アンチCSRFトークンを開きます。
対象サイトでは、「_token」という名前のパラメータでしたので、トークンを追加します。
デフォルトで追加されていました。もし一覧にトークンがない場合は、追加しましょう。

次に動的スキャンを開きます。
「Handle anti-CSRF tokens.」にチェックが入っていることを確認します。

ちなみに、v2.10.0では「アンチCSRFトークン利用(テスト実装)」となっていました。
新しいバージョンでは実装が正式に採用されたようですね。

CSRF対策ページに攻撃
それでは攻撃を行ってみましょう。
CSRF対策されているPOSTリクエストに対して動的スキャンを行いました。

GETリクエストと、POSTリクエストが交互に呼ばれていました。
POSTリクエストのステータスコードが、「200 OK」で返って来ていますので成功しています。

GETリクエストのレスポンスを確認します。
一度GETでレスポンスを受け取り、新しいトークンを取得しているのが分かります。

今度は、POSTデータのリクエストの中身を確認しましょう。
送信データに含まれるトークンが、新しいトークンに書き換えて送信されていました。

念の為、アンチCSRFの設定を無効にして実施してみました。

GETリクエストは送信されず、POSTリクエストのみ送信され、CSRF対策に弾かれているのが分かります。
(Laravelはステータスコード:419を返却します)

スキャン時に登録された古いトークンがそのまま使われており、サーバーサイドで弾かれてしまいます。

さいごに
CSRFの対策がされているサイトに対して、脆弱性診断を行いました。
是非OWASP ZAPを利用して、脆弱性のないサイトを構築しましょう。
他にも私のブログで、ツールについて解説している記事がありますのでご覧ください。
コメント