Web セキュリティ

CSRF (クロスサイトリクエストフォージェリ)

約 3 分で読めます

CSRF (クロスサイトリクエストフォージェリ) とは

CSRF (Cross-Site Request Forgery) とは、ユーザーが認証済みの Web サイトに対して、ユーザーの意図しないリクエストを送信させる攻撃手法です。攻撃者は罠となる Web ページやメールを用意し、被害者がそれを閲覧した瞬間に、被害者のブラウザから標的サイトへ不正なリクエストが自動送信されます。

ブラウザは送信先のドメインに紐づく Cookie を、リクエストの発生元がどのページであるかに関わらず自動的に付与するため、被害者がログイン中であれば、攻撃者のリクエストも認証済みとして処理されます。パスワード変更、送金、メールアドレスの変更、商品の購入など、状態を変更する操作が攻撃の標的になります。

攻撃の仕組みと具体例

CSRF 攻撃は以下の流れで実行されます。

  1. 被害者が標的サイト (例: オンラインバンキング) にログインし、セッション Cookie がブラウザに保存される
  2. 被害者が攻撃者の用意した罠ページを閲覧する (メールのリンク、掲示板の投稿など)
  3. 罠ページに埋め込まれた HTML や JavaScript が、被害者のブラウザから標的サイトへリクエストを送信する
  4. ブラウザがセッション Cookie を自動付与するため、標的サイトは正規のリクエストとして処理する

例えば、送金機能が POST /transfer で宛先と金額をリクエストボディから受け取る設計の場合、攻撃者は罠ページに自動送信フォームを埋め込むだけで、被害者の口座から送金を実行できます。フォームを画面外の iframe に置いて JavaScript で送信すれば、被害者は操作が起きたことに気づきません。

XSS と混同されやすいですが、CSRF は攻撃者のスクリプトを被害者のブラウザで実行するのではなく、被害者のブラウザから正規のリクエストを偽造する点が根本的に異なります。

防御策の実装

CSRF 対策は、リクエストが正規のユーザーの意図に基づくものであることを検証する仕組みを導入することが核心です。

CSRF トークン

サーバーがフォームの表示時にランダムなトークンを生成し、hidden フィールドに埋め込みます。フォーム送信時にトークンの一致を検証することで、外部サイトからの偽造リクエストを拒否します。この方式は同期トークンパターン (Synchronizer Token Pattern) と呼ばれ、トークンはセッションごとに一意で、同一オリジンポリシーにより外部サイトの JavaScript からは読み取れません。ただし XSS が存在するとトークンごと盗み出せるため、CSRF トークンは XSS 対策と組み合わせて初めて機能します。サーバー側にトークンを保持したくない場合は、署名付きの値を Cookie とリクエストの両方に載せて突き合わせる二重送信 Cookie 方式が代替になります。

SameSite Cookie 属性

Cookie の SameSite 属性を設定することで、クロスサイトリクエストへの Cookie 付与を制御できます。

  • SameSite=Strict: 外部サイトからのすべてのリクエストに Cookie を付与しない。最も安全だが、外部リンクからのアクセス時にもログイン状態が維持されない
  • SameSite=Lax: トップレベルナビゲーション (リンクのクリック) の GET リクエストにのみ Cookie を付与する。POST リクエストには付与されないため、多くの CSRF 攻撃を防げる。ただし属性が未指定で既定として Lax が適用される場合はより緩く扱われ、Cookie の発行から 2 分以内の POST リクエストには付与される
  • SameSite=None: クロスサイトリクエストにも Cookie を付与する。Secure 属性との併用が必須

SameSite 属性は多層防御として有効ですが、単独では CSRF 対策になりません。同一サイトの判定は登録可能ドメイン単位で行われるため、app.example.com が発行した Cookie は other.example.com からのリクエストでも同一サイト扱いになり、サブドメインの乗っ取りや共有ドメイン上の第三者コンテンツが抜け道になります。外部サービス連携で SameSite=None を指定せざるを得ない Cookie や、既定が適用されない旧来のブラウザ・組み込みブラウザも残るため、トークン検証と必ず併用してください。

その他の対策

  • Origin / Referer ヘッダーの検証: リクエストの送信元が自サイトであることを確認する。ただし、プライバシー設定やプロキシにより Referer が送信されない場合がある
  • カスタムヘッダーの要求: HTML フォームからは任意のヘッダーを付けられないため、X-Requested-With のような独自ヘッダーを必須にするとフォーム経由の偽造リクエストを弾ける。クロスサイトの JavaScript から付与するには CORS のプリフライトが必要になるが、Access-Control-Allow-Credentials を有効にしたまま許可オリジンを広げるとこの防御は成立しないため、許可オリジンは最小限に絞る
  • セキュリティヘッダーとの役割分担: CSP や X-Frame-Options は CSRF そのものを止める仕組みではない。CSRF は Cookie の付与条件とリクエスト元の検証で防ぎ、セキュリティヘッダーは XSS やクリックジャッキングという別経路を塞ぐものとして切り分けて設計する

フレームワーク組み込みの CSRF 対策

サーバーサイドの Web フレームワークの多くは、CSRF 対策を組み込みで提供しています。

  • Django: CsrfViewMiddleware が既定で有効で、テンプレートの {% csrf_token %} タグが埋め込んだトークンを検証する。HTTPS では Origin ヘッダーを CSRF_TRUSTED_ORIGINS と照合するため、サブドメイン経由の攻撃にも対応する
  • Ruby on Rails: 新規作成したアプリケーションでは config.action_controller.default_protect_from_forgery が有効なため、トークンの生成と検証が自動で行われる。明示的に指定する場合は protect_from_forgery with: :exception を書く
  • Spring Security: POST など安全でない HTTP メソッドに対して既定で CSRF 保護が働く。Thymeleaf や JSP との統合を使う場合は CsrfToken がフォームへ自動的に埋め込まれる
  • Next.js / SPA: Cookie 認証を使う API ルートでは SameSite Cookie と Origin ヘッダーの検証を組み合わせる。WAF による追加の保護も検討する

フレームワークの CSRF 保護を無効化する場合は、代替の対策が確実に実装されていることを検証してください。API エンドポイントで CSRF 保護を除外する場合は、認証トークン (Bearer Token) による認証に切り替え、Cookie ベースの認証を使用しないことが前提です。

よくある誤解

GET リクエストでは CSRF は発生しない
GET リクエストでも状態を変更する操作 (削除、設定変更など) を実装していれば CSRF の対象になる。img タグの src 属性に URL を設定するだけで GET リクエストを送信できるため、状態変更は必ず POST/PUT/DELETE で実装すべき。SameSite=Lax が既定になっても Lax は GET を安全なメソッドとして通すため、GET で状態を変更する実装はブラウザ側の既定では守られない。
HTTPS を使っていれば CSRF は防げる
HTTPS は通信の暗号化と改ざん防止を提供するが、CSRF とは無関係。CSRF は正規のユーザーのブラウザから正規のリクエストを送信させる攻撃であり、通信が暗号化されていても攻撃は成立する。
共有する

関連用語

関連記事