
CSRFトークンをPythonで実装する|"意図しない操作"を防ぐ
2026-09-17 ・ 実践
CSRF(クロスサイトリクエストフォージェリ) は、ログイン中のユーザーを騙して「本人が意図しない操作」(送金・退会・設定変更など)を実行させる攻撃です。防御の定番 同期トークン方式 をPythonで実装し、正規リクエストの見分け方を理解します。
なぜ起きるのか:ブラウザが自動でCookieを送る
ユーザーがサイトAにログイン中、悪意あるサイトBが「Aへのリクエスト」を仕込むと、ブラウザはAのcookieを自動で付けて送ってしまいます。サーバーから見ると本人の操作と区別がつかない——これがCSRFの急所です。
防御:予測できないトークンを要求する
対策は「サーバーが発行した推測不可能なトークンをフォームに埋め、送信時に照合する」こと。攻撃者はこのトークンを知り得ないので、偽リクエストは弾かれます。
同期トークン方式
トークン発行
セッションに保存
フォームに埋込
hidden項目
送信時に照合
一致のみ許可
準備
標準ライブラリのsecrets・hmacだけ。
① トークンの発行と検証
import secrets, hmac
# セッションごとにサーバーが保持するトークン(例では辞書で代用)
session_store = {}
def issue_token(session_id):
token = secrets.token_urlsafe(32) # 推測不可能なランダム
session_store[session_id] = token
return token
def verify_token(session_id, submitted):
expected = session_store.get(session_id)
if expected is None:
return False
return hmac.compare_digest(expected, submitted) # タイミング攻撃対策
② 正規リクエストと偽リクエスト
sid = "user-42"
csrf = issue_token(sid) # ページ表示時に発行しフォームへ埋め込む
# 正規の送信(フォームのトークンを一緒に送る)
print("正規:", verify_token(sid, csrf)) # True
# 攻撃者はトークンを知らないので当て推量になる
print("攻撃:", verify_token(sid, "guessed-token")) # False
正規リクエストだけTrue。攻撃サイトはsecrets.token_urlsafe(32)で作られた値を推測できないので、偽の操作リクエストは確実に弾かれます。
SameSite Cookie も強力
近年は Cookie の SameSite=Lax/Strict 属性で「他サイトからのリクエストにcookieを付けない」設定が広く使われ、CSRF対策の第一線になっています。トークン方式 + SameSite の併用が現在の定番です。
GETで状態を変えない
「クリックしただけ」で送金や削除が起きないよう、状態を変える操作は必ずPOST等にし、GETでは行わないこと。これはCSRF対策の前提です。フレームワークのCSRF保護機能を有効にするのが実務の基本です。
まとめ
- CSRFはブラウザがcookieを自動送信する性質を悪用する攻撃
- 対策は推測不可能な同期トークンを発行し、送信時に照合する
secrets.token_urlsafeで生成、hmac.compare_digestで照合- SameSite Cookie の併用と「状態変更はPOST」が前提
もう少し詳しく(背景と理論)
CSRF(クロスサイトリクエストフォージェリ)は、ログイン状態のユーザーに気づかせず、攻撃者のサイトから本物のサイトへ意図しないリクエストを送らせる攻撃です。ブラウザが Cookie を自動送信する性質を悪用します1。標準的対策が Synchronizer Token Pattern——サーバーが発行した予測不能なトークンをフォームに埋め込み、送信時に照合します(攻撃サイトはこのトークンを知り得ない)2。近年は Cookie の SameSite 属性(Lax/Strict)でクロスサイト送信自体を制限する防御も普及し、多層で守るのが実務です3。状態変更を伴う操作は必ず POST 等にし、GET で副作用を起こさないことも基本原則です。
次の一歩 🌸
出力側の対策はXSSとエスケープ、Web脆弱性の全体像はWebの脆弱性、認証トークンのJWT実装へどうぞ。