Hello there, ('ω')ノ
✅ 脆弱性の本質
通常、CSRFトークンはログインセッションごとに一意であり、「このトークンはこのユーザーだけが使えるもの」である必要があります。
しかし一部のアプリでは次のような致命的な設計ミスがあります:
発行済みトークンの「グローバルプール」さえ管理していれば良いと思っている
🎯 問題点
安全な実装 | 脆弱な実装 | |
---|---|---|
トークンはユーザーセッションに紐づく | トークンは誰のものでもよい | |
サーバー側で「このトークンはこのユーザーのもの」と検証 | 有効なトークン一覧に含まれていれば受け入れる |
🧠 攻撃者視点:この実装はCSRFにどう利用できるか?
攻撃の流れ
- 攻撃者が自分のアカウントでログイン
- 自分用のCSRFトークンを取得(例:フォームを開いてHTMLソースを見る)
- そのトークンを使った攻撃HTMLを作成
<form method="POST" action="https://vulnerable-website.com/email/change"> <input type="hidden" name="email" value="attacker@evil-user.net" /> <input type="hidden" name="csrf" value="attacker-valid-token" /> </form> <script> document.forms[0].submit(); </script>
- このHTMLを被害者に開かせると、自分のトークンが使われたCSRFリクエストが通ってしまう
✅ 攻撃が成立する理由
- アプリは「このトークンが有効か」しか見ておらず、
- 「このトークンが誰のものか」を見ていないため、攻撃者のトークンでも通る
⚠️ 危険なポイントまとめ
問題点 | 説明 | |
---|---|---|
トークンが「ユーザー固有」でない | トークンの意味をなしていない | |
攻撃者のトークンが被害者の操作に使える | 完全なCSRF防御バイパス |
✅ 正しい防御とは
実装 | 内容 | |
---|---|---|
トークンをセッションに紐づけて保存 | session['csrf_token'] = abc123 など |
|
リクエストのトークンとセッション内のトークンを厳密一致で照合 | request.POST['csrf'] == session['csrf_token'] |
|
トークンが他ユーザーから来ても絶対に通さない | 「誰が出したか」を必ず見る |
✅ まとめ
CSRFトークンは「値の正当性」だけでなく、「誰のトークンか」も重要。
- 単に「有効なトークン」かどうかしか見ていない実装では、
- 攻撃者が自分で発行したトークンを被害者に使わせることが可能になり、
- CSRF防御は完全に無効化されてしまいます。
Best regards, (^^ゞ