Session セキュリティ — Regenerate ID
テクノロジ系 / session-cookie (session / cookie / login / CSRF)
Session セキュリティ — Regenerate ID
Lesson 13 / Chapter 6
Session Fixation 攻撃って何
「攻撃者が 既に知っている Session ID をユーザーに使わせて、ログイン後の Session を乗っ取る」
1. 攻撃者がサイトにアクセス → サーバーから Session ID="ABC123" を取得 2. 攻撃者が罠リンクで ABC123 をユーザーに使わせる 例: https://target.example/?PHPSESSID=ABC123 3. ユーザーが ABC123 のまま target.example にログイン 4. サーバー: 「ABC123 さん、ログイン完了」 5. 攻撃者: ABC123 を自分のブラウザに設定 → ログイン状態を共有して乗っ取り
→ ログイン前後で Session ID が同じ ことが弱点。
防御策: session_regenerate_id(true)
<?php session_start(); $oldId = session_id(); // ログイン前の ID session_regenerate_id(true); // 新 ID を発行 + 古い Session を破棄 $newId = session_id(); // ログイン後の ID // $oldId !== $newId が保証される $_SESSION['user'] = ['name' => '太郎'];
| 引数 | 意味 |
|---|---|
true | 古い Session を破棄 (必須に近い) |
false (デフォルト) | 古い Session は残ったまま (危険) |
→ 必ず true を渡す。これを忘れると、固定化された ID も生き続けてしまう。
いつ呼ぶか
| タイミング | 理由 |
|---|---|
| ログイン直後 | ログイン前の ID で固定化されてもログイン後 ID で無効化される |
| 権限昇格時 (一般 → 管理者) | 同じ理由。重要操作の前に再生成 |
| ログアウト時 | session_destroy() するので不要だが、念のため再生成しても良い |
「何らかの権限が変わる瞬間に ID を作り直す」のが原則。
採点用: ID 変更を確認
<?php
// (採点用スタブ ... session の擬似化)
$oldId = session_id(); // 採点用は固定 ID "TESTSESSIONID"
session_regenerate_id(true);
$newId = session_id();
if ($oldId !== $newId) {
echo "changed: yes\n";
} else {
echo "changed: no\n";
}CLI でも session_regenerate_id() は新しい ID を生成してくれる。比較で「変わったか」を検証する。
他の防御策 (概念だけ)
| 対策 | 効果 |
|---|---|
session.cookie_httponly=1 | JS から PHPSESSID Cookie を読めなくする (XSS 経由の盗難を防ぐ) |
session.cookie_secure=1 | HTTPS 通信でしか PHPSESSID を送らない |
session.cookie_samesite=Lax | 他サイトからのリクエストに PHPSESSID を載せない (CSRF と二重防御) |
session.use_strict_mode=1 | サーバーが発行していない ID を拒否 |
php.ini または ini_set() で設定。全部 ON にしておけば固定化攻撃にも強くなる。
このチャプターでできるようになること
✅ Session Fixation が「事前に知った ID をユーザーに使わせて乗っ取る攻撃」と言える
✅ session_regenerate_id(true) を呼ぶ意味と引数の役割を説明できる
✅ ログイン時に必ず ID を再生成するコードを書ける
✅ 他の防御策 (httponly / secure / samesite / strict_mode) を 1 行で挙げられる
→ ドリルへ
考えてみよう
既定では正解・不正解の判定はしません。自分のペースで「答えを見る」を。採点してほしい場合だけ「採点してほしい」を押してください。
ドリル 01 — session_regenerate_id(true) で ID を作り直す
問題
ログイン時の Session ID 再生成を再現してください。
session_start()直後の Session ID (採点用スタブでTESTSESSIONID) を変数に保存session_regenerate_id(true)を呼ぶ- 再取得した Session ID と比較し、異なれば
"changed: yes"、同じなら"changed: no"を 1 行出力
期待される出力:
changed: yes
採点
php scripts/grade.php topics/session-cookie/ch06-session-security/drill/01-regenerate-id/
ヒント
$oldId = session_id(); @session_regenerate_id(true); $newId = session_id(); echo ($oldId !== $newId ? "changed: yes" : "changed: no") . "\n";
本物のセッション動作で確認したい場合
cd topics/session-cookie/ch06-session-security/drill/01-regenerate-id/ php -S localhost:8000 answer.php
ブラウザの開発者ツールで PHPSESSID を見ながらリロード、再生成のタイミングで Cookie 値が変わることを確認。
ドリル 02 — Session Fixation シナリオ — ログイン時に ID 再生成で防ぐ
問題
固定化攻撃のシナリオを 1 スクリプトで擬似化します。
シナリオ:
- 攻撃者から渡された ID
ATTACKERFIXEDIDで Session を開始 (採点用スタブでsession_id()をこの値にセット) - ユーザーがログイン処理を実行
- ログイン直後に
session_regenerate_id(true)を呼ぶ - ログイン後の Session ID が攻撃者の渡した固定 ID と 異なる ことを確認
出力仕様:
- 「ログイン前の ID」と「ログイン後の ID」が同じか異なるかを判定
- 異なれば
"safe: regenerated"、同じなら"vulnerable: fixation"を 1 行出力
期待される出力:
safe: regenerated
(session_regenerate_id(true) を呼ばないと vulnerable: fixation になる)
採点
php scripts/grade.php topics/session-cookie/ch06-session-security/drill/02-session-fixation/
ヒント
// スタブで session_id('ATTACKERFIXEDID') がセットされている前提
$oldId = session_id(); // ATTACKERFIXEDID
$_SESSION['user'] = ['name' => '太郎']; // ログイン
@session_regenerate_id(true); // ★ ここがポイント
$newId = session_id();
echo ($oldId !== $newId ? "safe: regenerated" : "vulnerable: fixation") . "\n";ポイント
- ログイン直後に必ず
session_regenerate_id(true)を呼ぶ のが固定化攻撃の最小防御 trueを渡し忘れると古い Session が残るので注意 (引数の名前はdelete_old_session)- ログアウト時の
session_destroy()と組み合わせて運用するのが定石