メインコンテンツへスキップ

実務で学ぶCSRF対策の本質|「SameSite=Laxで安心」は本当に正しいのか

··2184 文字·5 分

私は実務で、「CSRF対策は入れているはずなのに、セキュリティレビューで即差し戻された」という経験があります。理由は単純で、**「ブラウザがデフォルトで SameSite=Lax なんだから、もう対策は不要だろう」**という思い込みでした。

しかし、この判断はセキュリティのプロから見れば、**「Laxの仕様と攻撃シナリオを理解していない、極めて危険な考え方」**でした。

CSRF(Cross-Site Request Forgery)は、認証済みユーザーのブラウザを「踏み台」にして、意図しない操作を強制する攻撃です。本記事では、実務で実際に問題になったケースを交え、なぜ今でもCSRFトークンが必須なのか、そして現場で“合格”とされる標準的な対策を、理論+実装ベースで解説します。


1. CSRF攻撃の本質:なぜ「なりすまし」ではないのか
#

CSRF攻撃は、ユーザーのパスワードを盗む「なりすまし」ではありません。「正規のユーザーがログインしている状態のブラウザ」に、攻撃者が用意したリクエストを無理やり投げさせる攻撃です。

攻撃が成立するメカニズム
#

ブラウザには**「特定のドメインに対するCookieは、どのサイトからのリクエストであっても自動的に送信する」**という伝統的な仕様(アンビエント認証)があります。

  1. ユーザーが銀行サイト(bank.com)にログインし、セッションCookieがブラウザに保存される。
  2. ユーザーが別のタブで攻撃サイト(evil.com)を開く。
  3. 攻撃サイト内のスクリプトが POST bank.com/transfer?amount=1000000 を実行。
  4. ブラウザは「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点を徹底してください。

  1. 状態を変更する操作(Side Effect)には、絶対にGETを使わない。
  2. フレームワークのCSRF対策を「理由なく無効化」しない。
  3. SameSite属性は設定した上で、必ずサーバー側でのトークン検証を併用する。

セキュリティは「これくらいで大丈夫だろう」という慢心から崩れます。実装の仕組みを正しく理解し、多層防御(Defense in Depth)を常に意識することが、信頼されるエンジニアへの第一歩です。


📘 関連記事
#

🔗 参考資料
#

著者
ゆーふー
Web開発、インフラ、AI技術に興味があるエンジニアです。日々の学びを記録しています。

関連記事

👤 運営者プロフィール

運営者プロフィール画像

ゆーふー

メガベンチャーで働く現役Webエンジニア(歴約2年)。
フロントエンドからインフラ構築、セキュリティ対策まで、実務で得た「現場のリアルな技術知見」を発信しています。