セキュリティ・ID

CSRFとは|ログイン中のあなたの権限を、見知らぬサイトが借用する仕組み

CSRFとは具体的にどんな攻撃なのかSameSite Cookieを設定すればもう安全なのか個人開発でどこまで対策すればいいのか

あなたが銀行のサイトにログインしたまま、別タブで怪しいブログを開く。そのブログに埋め込まれた1枚の隠しフォームが、あなたのブラウザに送金リクエストを送信させる——あなたは何もクリックしていません。あなたの「ログイン済み」という状態だけが、勝手に利用されます

これがCSRF(Cross-Site Request Forgery)です。この記事では解説だけでなく、実際にコードを実行し、トークン検証がある場合とない場合で偽装リクエストの結果がどう変わるかを、本物の出力で示します。

この記事の要点

  • CSRFはログイン中のユーザーの権限を、別サイトが借用して意図しない操作を実行させる攻撃
  • 対策の基本はCSRFトークン——予測不能な値をフォームに埋め込み、送信時に照合する
  • SameSite Cookieは補助策。既定のLaxは危険なGETリクエストを守らないなど限界がある
  • 多くのフレームワークは標準機能でトークン検証を提供している。自作より標準機能を使う

定義と、実際にコードを動かして見る挙動

CSRFの本体は「セッションが有効なら何でも受け付ける」設計の欠陥。この記事のコードは実行した結果で、トークン検証の有無がそのまま被害の有無になる。

CSRFという攻撃名は、OWASPの定義に集約されています。“tricks an authenticated user's web browser into performing an unwanted action on a trusted site”。ログイン済みユーザーのブラウザを騙し、信頼されたサイト上で意図しない操作を実行させる——これがCSRFです。

実際に動かして確かめる

以下は編集部が実際にNode.jsで実行したコードと、その出力そのものです。

csrf-demo.mjs(実行済み。編集部環境で検証)javascript
const sessionTokens = new Map(); // sessionId -> csrfToken

// ❌ 脆弱: Cookie(セッション)が有効なら何でも実行する
function transferVulnerable(sessionId, toAccount, amount) {
  if (!sessionTokens.has(sessionId)) return { ok: false, reason: "未ログイン" };
  return { ok: true, reason: `${amount}円を${toAccount}へ送金完了` };
}

// ✅ 修正: リクエストに正しいCSRFトークンが含まれるかも検証する
function transferFixed(sessionId, toAccount, amount, submittedToken) {
  if (!sessionTokens.has(sessionId)) return { ok: false, reason: "未ログイン" };
  const expected = sessionTokens.get(sessionId);
  if (submittedToken !== expected) return { ok: false, reason: "CSRFトークン不一致(偽装リクエストを拒否)" };
  return { ok: true, reason: `${amount}円を${toAccount}へ送金完了` };
}
実行結果(そのまま。加工なし)text
=== 脆弱な実装(Cookieの有効性しか見ない) ===
悪意サイトが自動送信したフォーム(トークンなし):
{"ok":true,"reason":"500000円をattacker-accountへ送金完了"}

=== 修正後の実装(CSRFトークン検証あり) ===
悪意サイトが自動送信したフォーム(トークンを知らない):
{"ok":false,"reason":"CSRFトークン不一致(偽装リクエストを拒否)"}
正規の画面から送信(正しいトークン付き):
{"ok":true,"reason":"500000円をalice-own-savingsへ送金完了"}

結果が語ること

脆弱な実装は、悪意サイトからの偽装リクエストでも50万円の送金をそのまま実行しています。修正版はトークンを知らない偽装リクエストを拒否し、正規の画面からの送信だけを通しています。攻撃者はセッションCookieの値を知らなくても、被害者のブラウザに自動送信させるだけで成立する点が、この攻撃の厄介さです。

A Cross-Site Request Forgery (CSRF) attack occurs when a malicious web site, email, blog, instant message, or program tricks an authenticated user's web browser into performing an unwanted action on a trusted site.
出典OWASP Cheat Sheet Series「Cross-Site Request Forgery Prevention Cheat Sheet」 一次情報を確認2026-08-14 この内容の有効期限2027-02-14

対策の本命はトークン——フレームワークの機能をまず使う

自作のトークン検証より、フレームワーク標準のCSRF対策ミドルウェアを有効化する方が事故が少ない。自作が必要な場面は稀。

OWASPが推奨する主要な対策がSynchronizer Token Patternです。“CSRF tokens should be generated on the server-side”。トークンはサーバー側で生成し、セッションごとかリクエストごとに1回だけ発行する、というのが基本形です。

トークンに求められる性質

  • ユーザーセッションごとに一意 ── 使い回さない
  • 秘匿性 ── 第三者から推測・取得できない
  • 予測不能性 ── 暗号学的に安全な乱数で生成する

多くの場合、自分で実装する必要はない

Django・Rails・Laravel・Next.jsのAPI Routesなど、主要フレームワークの多くはCSRF対策のミドルウェアを標準または準標準で提供しています。個人開発の現実的な第一歩は、自作のトークン検証を書くことではなく、既にある機能を有効化して外していないか確認することです。無効化されているケースの多くは、開発中にエラーを避けるため一時的に外して、そのまま忘れられたパターンです。

CSRF tokens should be generated on the server-side and they should be generated only once per user session or each request.
出典OWASP Cheat Sheet Series「CSRF Prevention」(Synchronizer Token Pattern) 一次情報を確認2026-08-14 この内容の有効期限2027-02-14

「SameSite=Laxを設定したから安全」の落とし穴

SameSite CookieはCSRF対策の一部であって全部ではない。トークン検証との併用が前提で、単独運用には既定値Laxの穴が残る。

近年ブラウザの既定値になったSameSite Cookieは、強力だが万能ではありません。OWASPは明確に線を引いています。“it does not replace a proper CSRF defense in most deployments”。多層防御の一部として有効だが、多くの環境で適切なCSRF対策の代替にはならない、という位置づけです。

既定値Laxが守らないもの

既定値のLaxは安全でないメソッド(POST等)のクロスサイト送信だけをブロックし、GETリクエストは通します。状態を変更する処理をGETで実装している(削除ボタンをGETリンクで作る等)と、SameSite=Laxがあってもこの経路は守られません。

ドメイン共有時のリスク

SameSiteの判定はオリジン単位ではなく登録可能ドメイン単位で行われます。同じ親ドメインを共有するサブドメイン間では、SameSiteのクロスサイト判定をすり抜ける経路が生まれ得ます。この2点から、SameSite設定とCSRFトークンは両方入れるのがOWASPの結論です。関連するセッション管理の話は認可設計とIDORの記事でも扱っています。

SameSite is useful as a defense-in-depth control but it does not replace a proper CSRF defense in most deployments.
出典OWASP Cheat Sheet Series「CSRF Prevention」(SameSite Cookieの限界) 一次情報を確認2026-08-14 この内容の有効期限2027-02-14

よくある質問

CSRFとXSSは何が違いますか?
XSSは悪意あるコードを標的サイト内に注入して実行させる攻撃、CSRFは標的サイトの外から偽のリクエストを送りつける攻撃です。XSSは「サイトの中に入り込む」、CSRFは「サイトの外からなりすます」という違いがあります。
SameSite=Strictを設定すれば十分ですか?
有効な防御層ですが、OWASPは「多くの環境で適切なCSRF対策の代替にはならない」としています。ブラウザ間の実装差や、サブドメイン共有時のリスクもあり、CSRFトークンとの併用が推奨されます。
GETリクエストなら安全ですか?
GETで状態を変更する設計自体がアンチパターンです。SameSite=Laxの既定値はGETリクエストのクロスサイト送信をブロックしないため、GETで削除や更新ができる実装は特に危険です。
個人開発では何をすればいいですか?
多くのWebフレームワークにCSRF対策のミドルウェアが標準か準標準で用意されています。自作するより、まずフレームワークの機能を有効にすることが最初の一歩です。

まとめ

  • CSRFはログイン中の権限を外部サイトが借用する攻撃。クリック1つ・訪問だけで発火することもある
  • 対策の本命はCSRFトークンの検証。セッションだけでは不十分
  • SameSite Cookieは有効だが単独では不十分な多層防御の1つ
  • フレームワーク標準の対策機能をまず有効化するのが個人開発の現実的な出発点

今日から始められること

  1. 使っているフレームワークのCSRF対策機能(ミドルウェア)が有効か確認する
  2. 状態を変更するAPIがGETメソッドになっていないか確認する
  3. Cookieのsame-site属性を設定する(トークン対策と併用)
  4. フォーム送信・重要操作にCSRFトークンが含まれているか、開発者ツールで確認する

実務で組んだCSRFのワークフローには、値段が付きます

同じ課題を持つ会社にとって、動いている設定は「作る時間」を買えるということです。ServiceDockは自作のワークフローやテンプレートを出品できるマーケットプレイスです。手数料や出品の流れは出品者向けページにまとまっています。

出品の仕組みを見る