私は実務で、「CSRF対策は入れているはずなのに、セキュリティレビューで即差し戻された」という経験があります。理由は単純で、**「ブラウザがデフォルトで SameSite=Lax なんだから、もう対策は不要だろう」**という思い込みでした。
しかし、この判断はセキュリティのプロから見れば、**「Laxの仕様と攻撃シナリオを理解していない、極めて危険な考え方」**でした。
CSRF(Cross-Site Request Forgery)は、認証済みユーザーのブラウザを「踏み台」にして、意図しない操作を強制する攻撃です。本記事では、実務で実際に問題になったケースを交え、なぜ今でもCSRFトークンが必須なのか、そして現場で“合格”とされる標準的な対策を、理論+実装ベースで解説します。
1. CSRF攻撃の本質:なぜ「なりすまし」ではないのか#
CSRF攻撃は、ユーザーのパスワードを盗む「なりすまし」ではありません。「正規のユーザーがログインしている状態のブラウザ」に、攻撃者が用意したリクエストを無理やり投げさせる攻撃です。
攻撃が成立するメカニズム#
ブラウザには**「特定のドメインに対するCookieは、どのサイトからのリクエストであっても自動的に送信する」**という伝統的な仕様(アンビエント認証)があります。
- ユーザーが銀行サイト(bank.com)にログインし、セッションCookieがブラウザに保存される。
- ユーザーが別のタブで攻撃サイト(evil.com)を開く。
- 攻撃サイト内のスクリプトが
POST bank.com/transfer?amount=1000000を実行。 - ブラウザは「bank.comへのリクエストだから、Cookieを添えて送ろう」と判断し、正規の認証情報を添えてリクエストを投げてしまう。
2. なぜ「SameSite=Lax」だけでは不十分なのか#
現代のブラウザでは SameSite=Lax がデフォルトですが、これが完全な盾にならない理由は、**Laxの「例外規定」**にあります。
Laxの挙動#
- POST/PUTなどの非安全なリクエスト: 外部サイトからの送信時にはCookieを付与しない(ここで多くのCSRFを防げる)。
- GETリクエストによるトップレベルナビゲーション: 外部サイトのリンクをクリックして移動する場合などは、Cookieが送信される。
つまり、以下のケースでは依然として脆弱です#
- 副作用のあるGETメソッド:
/admin/delete-user?id=123のような、GETでデータを変更するエンドポイント。 - Laxのバイパス手法: 攻撃者がGETリクエストを巧妙に使い、ユーザーを特定のページへ誘導して状態を変更させる。
SameSite属性は「盾」ではなく「柵」です。乗り越える方法は存在するため、サーバーサイドでの検証(CSRFトークン)との二重防御が不可欠です。
3. 実務で推奨される具体的な対策パターン#
現場で“OK”が出る対策は、大きく分けて以下の2つです。
パターンA:Synchronizer Token Pattern(主流)#
サーバー側でランダムな値を生成し、セッションに保存。同時にHTMLのフォーム等に埋め込み、リクエスト時に一致するか検証します。
- メリット: 最も確実で、古くから使われている標準的な手法。
- 注意点: サーバー側でセッション状態(ステート)を管理する必要がある。
パターンB:Double Submit Cookie(SPA向け)#
Cookieとリクエストヘッダー(またはリクエストボディ)の両方に、同じランダムなトークンを乗せて送る手法です。
- メリット: サーバー側でトークンを保持する必要がなく、ステートレスなAPIと相性が良い。
- 仕組み: 攻撃者はCookieを「送信」させることはできても、JavaScriptでCookieの値を「読み取る(盗む)」ことは(Same-Origin Policyにより)できないため、正しいヘッダーを付与できないことを利用します。
4. 【実例】実地レビューで指摘された「落とし穴」#
筆者が実際にレビューで指摘された、よくある間違いです。
- 「管理画面は内部ネットワークだから不要」: フィッシング等で管理者のPCが踏み台になれば、内部ネットワーク越しに攻撃が成立します。
- 「JSON APIだから安全」: 以前は
Content-Type: application/jsonであればCSRFは難しいとされていましたが、HTMLの<form>からでもplain/textとして無理やりJSONを送る手法などが存在します。 - 「CORSを設定しているから大丈夫」: CORS(Cross-Origin Resource Sharing)は「リソースの読み取り」を制限するものであり、リクエストの「送信(書き込み)」そのものを防ぐものではありません。
5. まとめ:エンジニアが守るべき「三則」#
実務でCSRF対策を設計する際は、以下の3点を徹底してください。
- 状態を変更する操作(Side Effect)には、絶対にGETを使わない。
- フレームワークのCSRF対策を「理由なく無効化」しない。
- SameSite属性は設定した上で、必ずサーバー側でのトークン検証を併用する。
セキュリティは「これくらいで大丈夫だろう」という慢心から崩れます。実装の仕組みを正しく理解し、多層防御(Defense in Depth)を常に意識することが、信頼されるエンジニアへの第一歩です。











