この記事は学習用です。ChatGPT と GitHub Copilot を使っています。
1. 概要:CSRF とは何か
クロスサイトリクエストフォージェリ(CSRF: Cross-Site Request Forgery)は、ユーザーが意図しないリクエストを第三者に送信させられる攻撃である。
認証済みのユーザーが攻撃者の用意したページを閲覧すると、被害サイトに対して不正な操作(アカウント設定変更、送金、投稿など)が行われる。
例
- 銀行サイトにログインしたまま、攻撃者が用意したページを開く。
- 攻撃者ページ内の
<img src="https://bank.example.com/transfer?to=attacker&amount=1000">
が実行され、GET による送金が行われる(被害サイトが GET で状態変更を受け付けていた場合)。
2. 攻撃が成立する条件
CSRF は以下の条件が揃うと発生する。
条件 | 内容 |
---|---|
1 | ユーザーが正規サイトにログイン済みで、認証情報(Cookie など)が有効である |
2 | 攻撃者が任意のリクエストを被害サイトに送信させるページを用意できる |
3 | 被害サイトがリクエスト元を検証せずに処理してしまう |
特に、Cookie ベースのセッション認証を採用している場合、リクエスト時にブラウザが自動で Cookie を送信するため攻撃が成立しやすい。
3. 攻撃フロー(Mermaid 図)
以下は CSRF 攻撃の典型的な流れである。
sequenceDiagram
participant U as ユーザー
participant A as 攻撃者サイト
participant S as 正規サイト
U->>S: ログイン(Cookie 発行)
U->>A: 攻撃者サイトにアクセス
A->>S: 不正リクエストのトリガー
note over A,S: ユーザーのブラウザが Cookie を自動送信
S->>A: 操作成功(意図しないデータ変更)
このように、ブラウザが自動的に Cookie を送信してしまう点が根本的な要因である。
4. 対策:CSRF トークンの導入
最も一般的な防御方法は CSRF トークン(ワンタイムトークン、ノンス)を使用することである。
仕組み
- サーバーはフォームを生成するとき、推測困難なランダム値のトークンを付与する。
- クライアントはフォーム送信時にそのトークンを送信する(隠しフィールドやカスタムヘッダ)。
- サーバーは受け取ったトークンをセッション内の値などと比較する。
- 一致しない場合はリクエストを拒否する。
コード例(Python/Flask)
@app.route('/transfer', methods=['POST'])
def transfer():
token = request.form.get('_csrf_token')
if token != session.get('_csrf_token'):
abort(403)
process_transfer()
return 'OK'
このように、フォーム送信ごとに検証可能なトークンを使うことで、外部サイトからの偽装を防ぐ。
5. その他の防御手法
方法 | 内容 |
---|---|
SameSite Cookie 属性 | Cookie の送信を同一サイト発行のリクエストに限定する(SameSite=Lax または Strict )。多くのブラウザで未指定時は Lax 相当として扱われる。なお、SameSite=None を用いる場合は Secure 属性が必須。 |
Referer/Origin チェック | リクエストヘッダの送信元ドメインを検証する(Origin 優先、なければ Referer )。 |
多要素認証(MFA)/二要素認証(2FA) | 重要操作にワンタイムパスコードなどを要求する。 |
API 設計の見直し | 状態変更は POST/PUT/DELETE に限定し、CORS を厳格に設定する。ただし CORS だけでは CSRF は防げない点に留意。 |
これらを組み合わせ、多層防御(Defense in Depth)でトークン管理の不備を補完する。
6. フロントエンドにおける実装ポイント
JavaScript フレームワーク(例:React, Vue.js)でも CSRF 対策は必須である。
- SPA(Single Page Application)では、トークンを
meta
タグ等から読み取り、リクエストヘッダに含める。
axios.defaults.headers.common['X-CSRF-Token'] =
document.querySelector('meta[name="csrf-token"]')?.content ?? '';
- サーバー側では、ヘッダ内のトークンを照合する。XSS 対策(エスケープ、CSP など)も前提とする。
7. よくある誤りと注意点
誤り | 問題点 |
---|---|
GET メソッドで状態変更を行う | キャッシュやリンククリックで容易に実行される。副作用のある操作は禁止する。 |
トークンを Cookie のみで検証する | Cookie は自動送信されるため CSRF 防御にならない。ダブルサブミットクッキー等、Cookie とフォーム/ヘッダ双方での一致検証が必要。 |
同一トークンを長期間使い回す | 漏えい時の影響が大きく、リプレイ攻撃のリスクが高まる。適切な失効とローテーションを行う。 |
CSRF 対策は単一の手段では不十分であり、複数の防御を重ねることが重要である。
8. まとめ
- CSRF は「認証済みユーザーを悪用して不正操作を行わせる攻撃」。
- トークン検証・SameSite 属性・送信元検証などを併用して防御する。
- 実装段階で「リクエストがどの経路から来るか」を常に意識することが、安全な Web アプリ設計の第一歩となる。
A. 参考サイト
OWASP: Cross-Site Request Forgery (CSRF)
MDN Web Docs: SameSite cookies
Django Docs: CSRF protection
コメント