WordPressで考えるSameSite Laxの落とし穴|GETに見せかけてPOSTとして処理されるCSRF

CSRF対策としてSameSite Cookieを利用しているサイトは多いですが、実装によっては防御を簡単に回避されるケースがあります。

この記事では、Web Security Academyのラボ「SameSite Lax bypass via method override」をもとに、

  • SameSite=Laxがどのように機能するのか
  • なぜGETリクエストで攻撃が成立するのか
  • WordPressで起こり得る実装ミス

を整理します。

CSRFの基本的な仕組みがあいまいな場合は、先にこちらを読むと理解しやすくなります。

CSRFの仕組みまとめ|成立条件と対策の基本

SameSite Lax bypass via method overrideラボの概要

対象機能はメールアドレス変更です。

  • CSRFトークンなし
  • セッションCookieはSameSite未設定(=Lax扱い)
  • エンドポイントはPOSTのみ受け付け

一見すると、SameSiteによりCSRFは防げているように見えます。


攻撃の流れ|GETリクエストでCSRFが成立するまで

攻撃の流れは以下の通りです。

  1. 被害者がログイン状態のブラウザを持っている
  2. 攻撃者が用意したページを開く
  3. そのページからGETリクエストが発生する
  4. SameSite=LaxによりCookieが送信される
  5. サーバーがそのリクエストをPOSTとして処理する

CSRFの成立理由

ポイントはブラウザとサーバーの認識のズレです。

ブラウザ側

  • GETリクエストとして送信
  • トップレベルナビゲーション → Cookieを付与(Laxの条件を満たす)

サーバー側

  • _method=POSTを解釈 → POSTリクエストとして処理

結果

  • ブラウザ:GETだから安全と判断
  • サーバー:POSTとして処理

CSRF成立

「トークンが存在しない」「検証が甘い」といった問題と組み合わさると、さらに深刻になります。

WordPressで考えるCSRF対策の落とし穴|トークン未送信で突破されるケース


なぜSameSite=Laxでも防げないのか

SameSite=LaxはCSRF対策として一定の効果がありますが、完全ではありません。

理由は、トップレベル遷移ではCookieが送信されるという仕様にあります。

SameSite=Laxの挙動

SameSite=Laxでは、次のような場合にCookieが送信されます。

  • ユーザーがリンクをクリックしたとき
  • アドレスバー遷移などの通常のページ移動(GETリクエスト)

一方で、以下のようなケースではCookieは送信されません。

  • フォームのPOST送信
  • iframeや画像などのサブリクエスト

このラボで起きていること

このラボでは、本来POSTで処理されるべき機能に対して、

GET + _method=POST

という形でリクエストを送ることができます。

つまり、

  • リクエストとしてはGET(ブラウザはCookieを送る)
  • サーバー側ではPOSTとして処理される

というズレが発生しています。

なぜ攻撃が成立するのか

攻撃者は、次のようなスクリプトを用意します。

<script>
document.location = "https://example.com/change-email?email=hacker@example.com&_method=POST";
</script>

これを被害者が開くと、

  1. ページ遷移(トップレベルのGET)が発生する
  2. SameSite=LaxによりCookieが送信される
  3. サーバーはPOSTとして処理する
  4. ログイン済みユーザーとしてメールアドレスが変更される

という流れになります。

まとめ

SameSite=Laxが防げるのは、自動送信されるPOSTリクエストです。

しかし、ユーザー操作を伴うGETリクエストは防げません。

このように、ブラウザの挙動とサーバー側の実装にズレがあると、SameSiteに依存した対策は簡単に回避されてしまいます。


攻撃者視点でどう見えるか

この機能を見たとき、攻撃者はこう考えます。

  • CSRFトークンがない → 攻撃できそう
  • SameSite=Lax → POSTは無理だがGETなら可能
  • GETは使えない → ではPOSTとして処理させる方法はないか?

ここで「method override」に気づけば突破できます。

実際の攻撃は、こうした複数の弱点を組み合わせて成立します。

WordPressで考えるCSRFトークンの欠陥│セッションと紐づいてないトークンはなぜ危険なのか


WordPressで起こり得る実装ミス

WordPressでも同様の構造は普通に発生します。

① REST APIでのメソッド上書き

一部のプラグインやカスタム実装では、

  • _method
  • X-HTTP-Method-Override

などを使ってHTTPメソッドを変更できるようにしている場合があります。

② GETで状態変更が可能な処理

  • メール変更
  • 設定更新
  • 注文処理

GETで処理できる構造は、SameSite=Laxと組み合わさると危険です。

③ nonce未検証

WordPressの標準対策はnonceですが、

  • nonce未実装
  • nonceがすべての経路で検証されていない

といったケースではCSRFが成立します。


セキュリティ診断でのチェックポイント

以下を確認することで、この種の問題は見つかります。

① GETで状態変更できないか

URLパラメータで状態が変わるかを確認

② メソッド上書きが使えないか

  • _method
  • X-HTTP-Method-Override

を付与して挙動を確認

③ SameSiteに依存していないか

SameSiteだけで防御している設計は危険

④ nonceが正しく検証されているか

すべての更新処理で検証されているか確認


対策|SameSiteに依存しないCSRF防御

① CSRFトークン(nonce)を必ず検証する

SameSiteは補助的な対策に過ぎません。

② GETで状態変更を行わない

  • GET:取得のみ
  • POST:更新処理

この原則を守ることが重要です。

③ メソッド上書きを安易に許可しない

不要な場合は無効化します。

④ SameSiteに依存しない設計

SameSiteは防御の一部であり、単体では不十分です。


まとめ|SameSiteだけでは不十分な理由

SameSite=LaxはCSRF対策として有効ですが、完全ではありません。

特に以下の条件が揃うと簡単に突破されます。

  • CSRFトークンがない
  • GETリクエストが許可されている
  • メソッド上書きが可能

「ブラウザはGETとして扱うが、サーバーはPOSTとして処理する」というズレが、攻撃の成立条件になります。

CSRF対策は単一の方法では不十分で、実装全体を通して考える必要があります。

関連記事もあわせて確認してください。

CSRFの基本と仕組み
WordPressで考えるCSRF対策の落とし穴|トークン未送信で突破されるケース
WordPressで考えるCSRFトークンの欠陥│セッションと紐づいてないトークンはなぜ危険なのか
WordPressで考えるCSRF対策の落とし穴|POSTリクエストのみの検証では防げない理由