概要

CSRF (Cross-Site Request Forgery) は、ログイン済みユーザーのブラウザを 悪用 して、本人の意図しないリクエストをサーバーに送らせる攻撃。被害者が銀行サイトにログインしたまま攻撃者の悪意ページを開くと、仕込まれた <form action="https://bank.example/transfer"> が自動送信され、被害者の Cookie と一緒に届く。サーバーから見れば「正規ユーザーの送金」にしか見えない。

対策の標準形が CSRF トークン。フォーム表示時に ランダム文字列 を生成して $_SESSION['csrf_token'] に保存し、同じ値を <input type="hidden" name="csrf_token"> にも埋め込む。送信時に $_POST['csrf_token']$_SESSION['csrf_token']hash_equals() で比較 し、不一致なら拒否。攻撃者のフォームには正規 Session 内のトークンが書けないので攻撃が成立しない。

比較に == ではなく hash_equals() を使うのは タイミング攻撃 対策。== だと一致する prefix の長さで応答時間が微妙に変わり、攻撃者が時間差から「先頭何文字までは合っている」を推測できる。hash_equals は必ず全文字を比較して時間差を消す、Web セキュリティの定番イディオム。

学習目標

ドリル

no 内容
01 トークンを生成して $_SESSION に保存 → 16 進文字数を出力
02 stdin からトークン文字列を受け取り、$_SESSION 内の正解と一致したら OK、違ったら NG

本物の Web で確認したい場合

cd topics/session-cookie/ch05-csrf/drill/01-token-generate/
php -S localhost:8000 answer.php

ブラウザでアクセスし、開発者ツールで PHPSESSID Cookie を見て、サーバー側で Session にトークンが保存されていることを確認 (実体はサーバー側ファイル)。

演習: ドリル 01 — CSRF トークンを生成して Session に保存

問題

CSRF 防御の出発点 — ランダムなトークンを生成して $_SESSION['csrf_token'] に保存 する処理を書いてください。

期待される出力:

length: 64

ヒント

$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
echo "length: " . strlen($_SESSION['csrf_token']) . "\n";

本物の Web で確認したい場合

cd topics/session-cookie/ch05-csrf/drill/01-token-generate/
php -S localhost:8000 answer.php

ブラウザのソース表示で hidden input にトークンが入っていることを確認 (本ドリルでは form を出力しないが、本物の Web では <input type="hidden" name="csrf_token" value="..."> を出す)。

演習: ドリル 02 — CSRF トークンを検証

問題

サーバー側が保持しているトークンと、フォーム送信で受け取ったトークンを hash_equals() で比較し、一致すれば OK、違えば NG を 1 行出力してください。

このドリルの入力例 (tests/input.txt):

csrf_token=EXPECTED_TOKEN_ABC123

期待される出力:

OK

別パターン (攻撃想定): csrf_token=AAAANG

ヒント

$_SESSION['csrf_token'] = 'EXPECTED_TOKEN_ABC123';

parse_str(trim(fgets(STDIN) ?: ''), $_POST);
$sent  = $_POST['csrf_token'] ?? '';
$saved = $_SESSION['csrf_token'] ?? '';

if (hash_equals($saved, $sent)) {
    echo "OK\n";
} else {
    echo "NG\n";
}

なぜ hash_equals

===== は比較に掛かる時間が値で変わる (タイミング攻撃の足掛かり)。hash_equals()一定時間で比較 する設計。

この章を AI に聞く

  1. 「ch05 — CSRF とトークン」のつまずきやすいポイントを、初学者向けに3つ教えてください

    💬 ChatGPT 📘 Claude ✨ Gemini

  2. 「ch05 — CSRF とトークン」について、自分の手で試せる練習問題を3つ出してください (難易度を上げながら)

    💬 ChatGPT 📘 Claude ✨ Gemini

  3. 「ch05 — CSRF とトークン」を学んだ後、次に学ぶと良いトピックは何ですか?理由も教えてください

    💬 ChatGPT 📘 Claude ✨ Gemini

🎉 受講お疲れさまでした!

ch05 — CSRF とトークン」を読み終えました。
学んだことを誰かに教えると、もっと記憶に残ります。

X で共有 Hatena LINE