ログイン後の Cookie(セッションID)は、サーバから見れば「あなたそのもの」です。XSS はそれを盗み、CSRF はそれに乗る。攻撃の入口は違っても、狙われる中心資産はいつも同じセッションです。
社内エンジニア向けセキュリティ勉強会(全6回)の第3回です。XSS・CSRF・セッション管理という散らかりやすい3トピックを「狙いはいつも1つ=セッション」という1本の背骨で束ね、Laravel 13.x と FuelPHP 1.x の両方で危険なコードと安全なコードを並べます。
疑似デモは2つ。反射型 XSS で検索語の script がそのまま実行されるところから、同じ穴で document.cookie を攻撃者へ送れてしまう(=セッションハイジャック成立)ところまで。そして CSRF では、罠ページを開いただけでログイン中のメールアドレスが書き換わるところまでを追跡します。サーバは「本物」と「便乗」を区別できない、という対策の思想的な核まで持っていきます。
扱うトピック
- XSS:反射型/格納型/DOMベースの違い、Laravel Blade の {{ }} と {!! !!}、FuelPHP の security.auto_filter_output(既定 true)と生出力の抜け道
- CSRF:Cookie が自動送信される性質への便乗、Laravel の @csrf と PreventRequestForgery による標準防御 vs FuelPHP の Security::check_token() 自前実装、共通化の設計
- SameSite の限界:Lax はクロスサイトの form POST や img は弾くが、トップレベルの GET 遷移には Cookie が付く。だから土台だけに頼らずトークンが要る
- セッション管理:HttpOnly / Secure / SameSite の3属性と効く脅威、セッション固定化とログイン時の ID 再発行(regenerate / rotate)
持ち帰る3つの結論
1. 出力はエスケープする = HttpOnly と合わせて「盗ませない」
2. 状態変更には CSRF トークンを必須にする = SameSite と合わせて「乗らせない」
3. ログイン時にセッションIDを再発行する = 「使い回させない」
レガシー保守(FuelPHP 1.x)でも「明日からできる」棚卸しと設定確認まで示します。
想定読者:認証は気にしたのに、その後のセッションを軽く見ていた"ちょっと前の自分"。
分類:XSS = CWE-79 / OWASP A03:2021 Injection、CSRF = CWE-352 / A01:2021 Broken Access Control、セッション固定化 = CWE-384 / A07:2021 Identification and Authentication Failures