あなたが銀行のサイトにログインしたまま、別タブで怪しいブログを開く。そのブログに埋め込まれた1枚の隠しフォームが、あなたのブラウザに送金リクエストを送信させる——あなたは何もクリックしていません。あなたの「ログイン済み」という状態だけが、勝手に利用されます。
これがCSRF(Cross-Site Request Forgery)です。この記事では解説だけでなく、実際にコードを実行し、トークン検証がある場合とない場合で偽装リクエストの結果がどう変わるかを、本物の出力で示します。
CSRFの本体は「セッションが有効なら何でも受け付ける」設計の欠陥。この記事のコードは実行した結果で、トークン検証の有無がそのまま被害の有無になる。
CSRFという攻撃名は、OWASPの定義に集約されています。“tricks an authenticated user's web browser into performing an unwanted action on a trusted site”。ログイン済みユーザーのブラウザを騙し、信頼されたサイト上で意図しない操作を実行させる——これがCSRFです。
以下は編集部が実際にNode.jsで実行したコードと、その出力そのものです。
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}へ送金完了` };
}
=== 脆弱な実装(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 CookieはCSRF対策の一部であって全部ではない。トークン検証との併用が前提で、単独運用には既定値Laxの穴が残る。
近年ブラウザの既定値になったSameSite Cookieは、強力だが万能ではありません。OWASPは明確に線を引いています。“it does not replace a proper CSRF defense in most deployments”。多層防御の一部として有効だが、多くの環境で適切なCSRF対策の代替にはならない、という位置づけです。
既定値の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
同じ課題を持つ会社にとって、動いている設定は「作る時間」を買えるということです。ServiceDockは自作のワークフローやテンプレートを出品できるマーケットプレイスです。手数料や出品の流れは出品者向けページにまとまっています。
出品の仕組みを見る