初級では「ログイン中の人を利用して勝手な操作をさせる」構図を見ました。中級では、なぜその対策が効くのかを仕組みから捉えます(守り全体は姉妹ユニット Webのセキュリティ(全体像))。
概要 — まず全体をつかむ
詳細 — 1段階ずつ追う
どう起きる?
CSRF の根っこは、ブラウザが対象サイトの Cookie を自動で付けるという性質です。あなたが正規サイトにログイン中なら、そのサイト宛のリクエストには(誰が発生源でも)ログイン状態の Cookie が付きます。
- あなたが正規サイト(例=銀行)にログイン中
- 攻撃者の「罠ページ」を開く
- 罠ページが、こっそり正規サイトへ「送金リクエスト」を送らせる
- ブラウザが正規サイトの Cookie を自動で付けるので、サーバは本人の操作だと勘違いする
ポイントは、攻撃者は Cookie の中身を盗む必要がないことです。送らせるだけでよい。だから盗聴対策(暗号化)では防げません。
アニメーション『CSRFの流れ(ログイン中を悪用)』を開く
- 被害者ブラウザ — 正規サイトにログイン中で、そのサイトのCookieを持っている利用者のブラウザ
- 正規サイト — 本人がログインしているサイト。Cookieが付いていれば本人の操作と信じてしまう
- 罠サイト — 攻撃者が用意したサイトやメール。被害者に勝手なリクエストを踏ませる
登場人物メモ:
- ※1 自動送信 — ブラウザが対象サイト宛リクエストに Cookie を勝手に付ける挙動
- ※2 安全なメソッド — GET など「取得だけで副作用を持たない」べき操作
やさしく言うと(初級)
ブラウザは、あるサイトへのリクエストに、そのサイトのCookie(ログイン状態)を自動で付けます。攻撃者はこれを悪用します。
- あなたが銀行サイトにログイン中
- 別の「罠ページ」を開く
- 罠ページが、こっそり銀行への「送金リクエスト」を送らせる
- ブラウザは銀行のCookieを自動で付けるので、銀行は本人の操作だと勘違いする
アニメーション『CSRFの流れ(ログイン中を悪用)』を開く
- 被害者ブラウザ — 正規サイトにログイン中で、そのサイトのCookieを持っている利用者のブラウザ
- 正規サイト — 本人がログインしているサイト。Cookieが付いていれば本人の操作と信じてしまう
- 罠サイト — 攻撃者が用意したサイトやメール。被害者に勝手なリクエストを踏ませる
どう防ぐ?
対策は「この操作は正規の画面から始まったか」を確かめることに集約されます。
- CSRFトークン — 推測できない値を正規フォームに埋め、送信時にサーバで照合する。罠ページはこの値を読めないので弾ける。なぜ効くか=攻撃者が用意できない情報を必須にするため
- SameSite Cookie — クロスサイト起点の(多くの)リクエストに Cookie を付けない設定。なりすましの前提(自動送信)を崩す(ただし既定の Lax では、リンク等のトップレベル GET 遷移には Cookie が付く。Strict や併用でさらに堅く)
- Origin/Referer チェック — リクエストの発生源が自サイトかをヘッダで確認する補助策
- 安全なメソッド設計 — 副作用のある操作を GET にしない。GET は「取得だけ」に保ち、状態変更は POST 等に限る
- 重要操作は再確認 — 送金などはパスワード再入力や MFA を挟む
アニメーション『SameSite Cookie の効き方』を開く
この部分をもっと深く(上級)
「正規の画面から始まった操作か」を確かめるトークンにも、二つの実装があります。仕組みと強弱が違います。
- 同期トークン(synchronizer) — サーバがセッションに正解値を保持し、フォームに埋めた値と突き合わせる。サーバ状態を持つぶん堅いが、サーバ側の管理が要る
- 二重送信クッキー(double-submit) — トークンをCookieとリクエスト本体の両方に入れ、一致するかだけを見る。サーバが状態を持たなくてよく水平スケールしやすい一方、サブドメインからのCookie上書きや中間者に弱く、署名付きや
__Host-接頭辞のホスト限定Cookieで補強する
粒度も設計点です。
- セッション単位 — ログイン中は同じトークンを使い回す。実装が軽い
- リクエスト単位 — 操作ごとに使い捨てる。漏洩時の影響を最小化できるが、複数タブや戻る操作と相性が悪く、実装が重い
トークンの置き場所は、URLに載せると Referer 経由で漏れうるため、フォーム値かカスタムヘッダで渡します(次節に続く)。
やさしく言うと(初級)
- CSRFトークン — 正規の画面に「予測できない合言葉」を埋め、送信時に照合する。罠ページはこの合言葉を知らないので弾ける
- SameSite Cookie — 他サイト起点のリクエストにはCookieを付けない設定
- 重要操作は再確認 — 送金などはパスワード再入力やMFAを挟む
⚠️ 気をつける
- 認証と混同 — ログイン(認証)していても防げない。CSRF は別軸の対策が要る
- GETで状態変更 — 「クリックしただけ」「画像を表示しただけ」で操作が起きる作りは危険(副作用のある操作は GET にしない)
- トークンの置き場所ミス — URL に露出させると Referer 経由で漏れうる。フォーム値やカスタムヘッダで渡す
- SameSite 過信 — 古いブラウザや例外的な遷移では抜ける場合があり、トークンと併用するのが基本
この部分をもっと深く(上級)
- GETは「取得だけ」に保つ — GETは仕様上、繰り返しても副作用のない安全なメソッドであるべき。状態変更をGETに載せると、画像タグ・プリフェッチ・リンク誘導だけで発火し、SameSite=Laxすら素通りする
- 多層で重ねる — SameSite(前提を崩す)+トークン(攻撃者が用意できない情報を必須にする)+Origin/Referer確認(発生源の照合)+重要操作の再認証(MFA)を積む。一枚が破れても次で止める。守り全体の位置づけは Webの中のセキュリティ を参照
- SameSite過信 — 既定Laxは万能ではない。トップレベルGET・古いブラウザ・例外遷移で抜けるため、トークン併用が基本
- 二重送信の署名忘れ — 素の二重送信はCookie上書きに弱い。署名や
__Host-接頭辞で固める
やさしく言うと(初級)
- 認証と混同 — ログイン(認証)していても防げない。CSRFは別対策が要る
- GETで状態変更 — 「クリックしただけ」で操作が起きる作りは危険(副作用のある操作はGETにしない)
理解度チェック
そのまま解けます(成績は保存されません)。無料アカウントを作ると、学習の記録と進捗の山登りが始まります。
問1. CSRFトークンが有効なのはなぜか、最も適切なのは?
問2. 「取得だけで副作用を持たない」べきとされ、状態変更を載せてはいけない HTTP メソッドは?大文字英字で答えてください。
問3. 送金などの重要操作で、パスワードに加えて複数の要素で本人確認する仕組みを英字3文字で何という?
問4. SameSite Cookie が CSRF 対策として働く理由は?
問5. CSRF が成立する根っこの原因はどれ?
問6. CSRF 攻撃について正しいのはどれ?
問7. Origin/Referer チェックの役割として正しいのは?
問8. CSRF トークンの受け渡し方として避けるべきなのはどれ?