CSRF

ユーザーが認証済みの Web サイトに対して、攻撃者が意図しないリクエストを送信させる攻撃手法

セキュリティWeb

CSRF とは

CSRF (Cross-Site Request Forgery、クロスサイトリクエストフォージェリ) は、ユーザーが認証済みの Web サイトに対して、攻撃者が用意した罠ページから意図しないリクエストを送信させる攻撃手法である。ブラウザが Cookie を自動送信する仕組みを悪用する。

OWASP Top 10 に長年ランクインしていた攻撃で、2013 年版では 8 位だった。SameSite Cookie の普及により脅威は低下したが、レガシーシステムや Cookie ベースの認証を使うアプリケーションでは依然として注意が必要だ。

攻撃の仕組み

1. ユーザーが銀行サイト (bank.example.com) にログイン
   → セッション Cookie がブラウザに保存される

2. ユーザーが攻撃者の罠ページ (evil.example.com) を閲覧

3. 罠ページに埋め込まれた HTML が銀行サイトへ POST リクエストを自動送信
   <form action="https://bank.example.com/transfer" method="POST">
     <input type="hidden" name="to" value="attacker-account" />
     <input type="hidden" name="amount" value="1000000" />
   </form>
   <script>document.forms[0].submit();</script>

4. ブラウザがセッション Cookie を自動付与
   → 銀行サイトは正規ユーザーからのリクエストと判断
   → 送金が実行される

攻撃者はユーザーの Cookie を盗む必要がない。ブラウザが自動的に Cookie を付与してくれるため、ユーザーが罠ページを開くだけで攻撃が成立する。

対策

CSRF トークン (Synchronizer Token Pattern)

フォームに一意なトークンを埋め込み、サーバーで検証する。最も伝統的で確実な対策だ。

<form action="/transfer" method="POST">
  <input type="hidden" name="_csrf" value="a1b2c3d4..." />
  <!-- フォームの内容 -->
</form>

攻撃者は CSRF トークンの値を知ることができないため、正しいトークンを含むリクエストを偽造できない。

SameSite 属性を設定すると、クロスサイトリクエストに Cookie を送信しなくなる。

動作 CSRF 防御
Strict クロスサイトリクエストに一切 Cookie を送信しない 完全に防御
Lax GET リクエストのみ Cookie を送信 (POST は送信しない) ほぼ防御
None 常に Cookie を送信 (Secure 必須) 防御なし

Chrome 80 以降、SameSite のデフォルト値が Lax に変更された。これにより、明示的に設定しなくても POST リクエストの CSRF は防御される。ただし、GET リクエストで副作用を起こす API (GET /delete-account) は Lax でも防御できない。

Origin / Referer ヘッダー検証

リクエストの Origin ヘッダーが自サイトのドメインと一致するか検証する。CSRF トークンの管理が不要で実装が簡単だが、一部のブラウザやプロキシが Origin ヘッダーを送信しないケースがある。

SPA + API 構成での CSRF

SPA が JWT を Authorization ヘッダーで送信する構成では、ブラウザが自動送信しないため CSRF のリスクは低い。

認証方式 CSRF リスク 理由
セッション Cookie 高い ブラウザが自動送信
JWT in Cookie 高い ブラウザが自動送信
JWT in Authorization ヘッダー 低い JavaScript で明示的に付与
JWT in localStorage 低い (XSS リスクあり) ブラウザが自動送信しない

JWT を Cookie に保存する場合は、SameSite=Strict と CSRF トークンの併用が推奨される。

API Gateway + Lambda での対策

API Gateway の CORS 設定で Access-Control-Allow-Origin を自サイトのドメインに限定する。* (ワイルドカード) は使わない。

# SAM テンプレート
Cors:
  AllowOrigin: "'https://example.com'"
  AllowMethods: "'GET,POST,PUT,DELETE'"
  AllowHeaders: "'Content-Type,Authorization'"
  AllowCredentials: true

CORS はブラウザが強制する仕組みであり、curl やサーバーサイドからのリクエストは制限できない。CORS だけに頼らず、認証・認可を適切に実装する。

CSRF を扱う関連書籍も多い。

関連用語