はじめに
CSRF 対策として広く知られる Double Submit Cookie。
「Cookie と hidden field の値を比較するから安全」——
本当にそうでしょうか?
本記事では、実際に Double Submit Cookie を突破した攻撃シナリオをもとに、
- なぜ防御が成立していなかったのか
- どの前提が破られた瞬間に崩壊したのか
- 開発者・ペンテスターが見るべき本当のチェックポイント
を 攻撃者視点 → 防御者視点の両方から解説します。
Double Submit Cookie とは(おさらい)
Double Submit Cookie は、サーバ側に CSRF Token を保存せず、
- Cookie に保存されたトークン
- フォームの hidden field に埋め込まれたトークン
この 2 つが一致するかを検証する方式です。
if ($_POST['csrf_token'] === $_COOKIE['csrf-token']) {
// 正当なリクエスト
}
設計上の前提(ここ重要)
この方式は、以下を暗黙に信頼しています:
- 攻撃者は Cookie を自由に設定できない
- CSRF Token は 推測・再生成できない
- Cookie のスコープは 厳密に管理されている
——本記事のケースでは、この 前提がすべて破られていました。
起こりうる脆弱なシナリオ
Double Submit Cookie は正しく実装されていれば有効な CSRF 防御策ですが、
攻撃者は常に「前提条件」を崩す方法を探しています。
以下は、実運用で確認されている代表的なバイパス手法です。
1. Session Cookie Hijacking(MITM / 情報漏洩)
CSRF Token が セッション Cookie と同一の保護境界に置かれている場合、
以下のような状況で 同時に漏洩する可能性があります。
- 公衆 Wi-Fi における盗聴
- マルウェア / ブラウザ拡張
- HTTPS 未強制の通信
- 不適切な Cookie 属性(Secure / HttpOnly 未設定)
CSRF Token が Session と一緒に盗まれた瞬間、防御は無意味になります。
2. Same-Origin Policy の迂回(Attacker Controlled Subdomain)
攻撃者が以下を満たす場合:
-
attacker.example.comを制御可能 - Cookie が
Domain=.example.comで発行されている - ブラウザがサブドメインからの Cookie 設定を許可
このとき、Same-Origin Policy は事実上破壊されます。
- 攻撃者はサブドメイン経由で Cookie を注入
- メインドメインの CSRF 防御を“内部から”突破
「同一オリジンだから安全」という前提が崩れる瞬間です。
3. XSS 脆弱性の悪用
アプリケーションに XSS が存在する場合、
Double Submit Cookie はほぼ無力化されます。
攻撃者は:
- Cookie から CSRF Token を直接取得
- ページ内 hidden field の値を取得
- 正規リクエストと完全一致する CSRF 攻撃を生成
XSS がある環境で CSRF 防御だけを議論するのは意味がありません。
4. Token 生成の予測・干渉
CSRF Token が以下のように生成されている場合、致命的です:
- ユーザー ID
- メールアドレス
- 銀行口座番号
- タイムスタンプ
- Base64 / Hash しただけの識別子
これらは:
- 推測可能
- 再生成可能
- 一度漏れたら恒久利用可能
CSRF Token は「識別子」ではなく「秘密鍵」であるべきです。
5. Subdomain Cookie Injection(本記事の核心)
関連サブドメインから Cookie を注入できる設計では、
攻撃者は以下を実現できます:
- 正規ドメイン向けの CSRF Cookie を強制設定
- フォーム側の Token と完全一致させる
- サーバに「正当なリクエスト」と誤認させる
Double Submit Cookie の最大の弱点がここです。
攻撃全体像(チェーン型 CSRF)
この攻撃は単独では成立しません。
複数の設計ミスが連鎖することで成立します。
脆弱性①:CSRF Token が「予測可能」
被害アプリケーションでは、CSRF Token が以下のように生成されていました。
csrf-token = base64_encode(銀行口座番号)
何が問題か?
- ❌ ランダム性ゼロ
- ❌ ユーザー情報から逆算可能
- ❌ 一度分かれば永久利用可能
攻撃者は CyberChef を使い、Token をデコードしただけで
「これは銀行口座番号だ」と即座に理解します。
CSRF Token は「識別子」ではありません。
秘密鍵レベルのランダム性が必要です。
脆弱性②:サブドメインから Cookie を注入できる
攻撃者は attacker.mybank.thm という 攻撃者管理サブドメインを持っていました。
そこから以下の Cookie を設定します:
setcookie(
'csrf-token',
base64_encode("GB82MYBANK5699"),
[
'domain' => 'mybank.thm',
'path' => '/',
'samesite' => 'Lax'
]
);
ここが致命点
Domain=mybank.thm- → サブドメインからメインドメインへ Cookie 注入可能
- SameSite=Lax は トップレベル遷移 POST を防げない
つまり:
攻撃者が「正しい CSRF Cookie」を
被害者のブラウザに合法的に植えられる状態でした。
攻撃シナリオ:パスワード変更 CSRF
① 被害者はログイン済み
- PHPSESSID は有効
- 銀行サイトはログアウトしていない
② フィッシングメールで誘導
件名:
Urgent: Suspicious Login Attempt Detected
リンク先:
https://attacker.mybank.thm
③ 攻撃者ページで自動処理
攻撃者サイトでは:
- CSRF Cookie を注入
- 偽の変更フォームを自動送信
<form action="http://mybank.thm/changepassword.php" method="POST">
<input type="hidden" name="csrf_token" value="復号済みトークン">
<input type="hidden" name="confirm_password" value="AttackerPassword">
</form>
<script>document.forms[0].submit()</script>
④ サーバ側の判定
if (
base64_decode($_POST['csrf_token']) ==
base64_decode($_COOKIE['csrf-token'])
) {
// パスワード変更
}
- Cookie:攻撃者がセット
- Form:攻撃者がセット
- PHPSESSID:被害者のもの
完全一致 → 正常リクエストと誤認
なぜ防げなかったのか(本質)
このケースの問題点は Double Submit Cookie 方式そのものではありません。
真の原因は:
| 問題 | 内容 |
|---|---|
| Token 設計 | 予測可能・可逆 |
| Cookie 設計 | サブドメイン注入許可 |
| 信頼モデル | Cookie = 安全という思い込み |
CSRF Token は「値」ではなく「秘密情報」
という認識が欠けていました。
正しい防御設計
正しい CSRF Token 生成
$token = bin2hex(random_bytes(32)); // 256bit
Cookie スコープ制御
-
Domainを極力指定しない - サブドメイン分離
-
__Host-Cookie Prefix の活用
追加防御(重要操作)
- パスワード変更時は 再認証
- Origin / Referer チェック併用
- XSS 対策(CSRF は XSS に弱い)
ペンテスター視点のチェックリスト
- CSRF Token は 何から生成されているか
- Token に ユーザー情報が混ざっていないか
- Cookie の Domain / Path 設定
- サブドメインの管理状態
- SameSite を過信していないか
まとめ
予測可能な CSRF Token は、存在しないのと同じ。
Double Submit Cookie は 正しく実装すれば有効ですが、
- Token 設計
- Cookie スコープ
- 信頼境界
これらを誤ると、むしろ攻撃を簡単にします。
