Shikata Ga Nai

Private? There is no such things.

LAB: CSRFトークンがセッションと紐づいていない脆弱性:他人のトークンで攻撃可能に

Hello there, ('ω')ノ

✅ 脆弱性の本質

通常、CSRFトークンはログインセッションごとに一意であり、「このトークンはこのユーザーだけが使えるもの」である必要があります。

しかし一部のアプリでは次のような致命的な設計ミスがあります:

発行済みトークンの「グローバルプール」さえ管理していれば良いと思っている


🎯 問題点

安全な実装 脆弱な実装
トークンはユーザーセッションに紐づく トークンは誰のものでもよい
サーバー側で「このトークンはこのユーザーのもの」と検証 有効なトークン一覧に含まれていれば受け入れる

🧠 攻撃者視点:この実装はCSRFにどう利用できるか?

攻撃の流れ

  1. 攻撃者が自分のアカウントでログイン
  2. 自分用のCSRFトークンを取得(例:フォームを開いてHTMLソースを見る)
  3. そのトークンを使った攻撃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>
  1. このHTMLを被害者に開かせると、自分のトークンが使われたCSRFリクエストが通ってしまう

✅ 攻撃が成立する理由

  • アプリは「このトークンが有効か」しか見ておらず、
  • 「このトークンが誰のものか」を見ていないため、攻撃者のトークンでも通る

⚠️ 危険なポイントまとめ

問題点 説明
トークンが「ユーザー固有」でない トークンの意味をなしていない
攻撃者のトークンが被害者の操作に使える 完全なCSRF防御バイパス

✅ 正しい防御とは

実装 内容
トークンをセッションに紐づけて保存 session['csrf_token'] = abc123 など
リクエストのトークンとセッション内のトークンを厳密一致で照合 request.POST['csrf'] == session['csrf_token']
トークンが他ユーザーから来ても絶対に通さない 「誰が出したか」を必ず見る

✅ まとめ

CSRFトークンは「値の正当性」だけでなく、「誰のトークンか」も重要。

  • 単に「有効なトークン」かどうかしか見ていない実装では、
  • 攻撃者が自分で発行したトークンを被害者に使わせることが可能になり、
  • CSRF防御は完全に無効化されてしまいます。

Best regards, (^^ゞ