Overview
CSRF(Cross-Site Request Forgery:クロスサイトリクエストフォージェリ)とは、Webアプリケーションに対する攻撃手法の一つで、ユーザーが認証済みの状態(ログイン中)であることを悪用し、ユーザーの意図しないリクエストを強制的に実行させる攻撃です。「シーサーフ」とも呼ばれます。
攻撃者は悪意のあるWebページやメールにリクエストを埋め込み、被害者がそのページを閲覧するだけで、被害者の認証済みセッションを利用してターゲットのWebアプリケーションに不正なリクエストが送信されます。パスワード変更、送金処理、メールアドレス変更など、State-Changing操作(状態を変更する操作)が主な攻撃対象となります。
CSRFはWebアプリケーションがリクエストの送信元を適切に検証していない場合に成立します。ブラウザがリクエストに自動的にCookieを付与する仕組みを悪用するため、認証にCookieを使用するすべてのWebアプリケーションが潜在的なリスクを持っています。OWASPでも長年にわたり重大なWebセキュリティリスクとして位置づけられてきました。
Details
CSRF攻撃の仕組み
CSRF攻撃は以下の流れで実行されます。まず、被害者がターゲットサイト(例:銀行サイト)にログインし、セッションCookieがブラウザに保存されます。次に、被害者が攻撃者の用意した悪意あるサイトを訪問します。悪意あるサイトには、ターゲットサイトへのリクエスト(例:送金リクエスト)が埋め込まれています。
ブラウザは同一ドメインへのリクエストに自動的にCookieを付与するため、被害者の認証情報がそのまま送信され、ターゲットサイトは正当なリクエストとして処理してしまいます。攻撃はHTML formの自動送信、imgタグのsrc属性、XMLHttpRequest、fetch APIなど様々な方法で実行可能です。
CSRFトークン
CSRFトークン(Anti-CSRF Token)は、CSRF攻撃を防御する最も基本的な手法です。サーバーがランダムで予測不可能なトークンを生成し、フォームの隠しフィールドやHTTPヘッダーに埋め込みます。リクエスト受信時にサーバーがトークンを検証し、一致しない場合はリクエストを拒否します。
トークンはセッションごと(またはリクエストごと)に一意に生成され、暗号学的に安全な乱数生成器を使用する必要があります。Synchronizer Token PatternとDouble Submit Cookie Patternの2つの主要な実装方式があります。フレームワークの多く(Django、Ruby on Rails、Spring等)にはCSRFトークン機能が組み込まれています。
SameSite Cookie属性
SameSite Cookie属性は、クロスサイトリクエスト時のCookie送信を制御するブラウザのセキュリティ機能です。以下の3つの値を設定できます。
- Strict:クロスサイトリクエストではCookieが一切送信されない。最も安全だが、外部サイトからのリンクでもCookieが送られないため、ユーザビリティに影響がある
- Lax:トップレベルナビゲーション(リンクのクリック等)のGETリクエストではCookieが送信されるが、POSTリクエストやiframe等からのリクエストでは送信されない。セキュリティと利便性のバランスが取れた設定
- None:すべてのクロスサイトリクエストでCookieが送信される。Secure属性との併用が必須。サードパーティCookieが必要な場合に使用
2020年以降、主要ブラウザはSameSite属性が未指定のCookieをデフォルトで「Lax」として扱うようになり、CSRF攻撃のリスクが大幅に低減されました。
Referer/Originヘッダー検証
サーバー側でHTTPリクエストのRefererヘッダーやOriginヘッダーを検証し、リクエストが自サイトから送信されたものかを確認する防御手法です。正規のドメインからのリクエストのみを受け付け、外部サイトからのリクエストを拒否します。
ただし、Refererヘッダーはプライバシー設定やプロキシにより省略される場合があるため、Originヘッダーの検証がより信頼性が高いとされています。この手法はCSRFトークンと併用することで、多層的な防御を実現できます。
Login CSRF
Login CSRFは、攻撃者が被害者のブラウザに攻撃者自身のアカウントでログインさせる特殊なCSRF攻撃です。被害者が気づかずに攻撃者のアカウントで操作を行い、個人情報(検索履歴、クレジットカード情報など)が攻撃者のアカウントに紐づけられてしまいます。
Login CSRFは通常のCSRF対策(CSRFトークン)では防御が難しい場合があります。ログイン前のフォームにもCSRFトークンを埋め込む、ログイン後にセッションIDを再生成する、ログイン処理にCAPTCHAを導入するなどの対策が有効です。
Security Measures
- 01CSRFトークンの実装:すべての状態変更リクエスト(POST、PUT、DELETE等)にCSRFトークンを要求してください。トークンはセッションごとに一意に生成し、暗号学的に安全な乱数生成器(CSPRNG)を使用しましょう。フレームワーク組み込みのCSRF保護機能を活用することを推奨します。
- 02SameSite Cookie属性の設定:セッションCookieにSameSite=Lax(またはStrict)属性を設定してください。これによりクロスサイトからのPOSTリクエストにCookieが付与されなくなり、多くのCSRF攻撃を防止できます。サードパーティCookieが不要な場合はStrictを推奨します。
- 03Originヘッダーの検証:サーバー側でリクエストのOriginヘッダーを検証し、信頼されたドメインからのリクエストのみを受け付けてください。Originヘッダーが存在しない場合はRefererヘッダーをフォールバックとして検証し、両方とも存在しない場合はリクエストを拒否しましょう。
- 04重要な操作に再認証を要求:パスワード変更、メールアドレス変更、送金処理など、特に重要な操作については現在のパスワードの再入力やMFAの追加認証を要求してください。CSRF攻撃が成功しても、再認証のステップで攻撃を阻止できます。
- 05GETリクエストの副作用を排除:GETリクエストでデータの変更や削除などの副作用のある処理を行わないでください。REST原則に従い、データの変更はPOST/PUT/DELETEメソッドを使用しましょう。imgタグやリンクを使った単純なCSRF攻撃はGETリクエストを悪用するため、この原則の遵守は重要です。
- 06カスタムHTTPヘッダーの活用:AJAXリクエストにカスタムHTTPヘッダー(例:X-Requested-With)を付与し、サーバー側で検証してください。ブラウザのCORS(Cross-Origin Resource Sharing)ポリシーにより、クロスオリジンのリクエストにカスタムヘッダーを付与するにはプリフライトリクエストが必要となり、CSRF攻撃を困難にします。
Incidents
📋 Netflix CSRF脆弱性(2006年)
2006年、NetflixのWebサイトにCSRF脆弱性が発見されました。攻撃者は悪意あるWebページを通じて、被害者のNetflixアカウントに対してDVDレンタルキューの変更、配送先住所の変更、アカウント認証情報(メールアドレスやパスワード)の変更など、あらゆるアカウント操作を実行できる状態でした。
この脆弱性はセキュリティ研究者によって報告され、Netflixは速やかに修正を行いました。当時はCSRF攻撃に対する認識がまだ低く、多くのWebサービスがCSRFトークンを実装していなかったため、この事例はWebアプリケーションセキュリティにおけるCSRF対策の重要性を広く認知させるきっかけとなりました。
📋 Gmail CSRF脆弱性(2007年)
2007年、GmailにCSRF脆弱性が発見され、攻撃者が被害者のGmailアカウントのメールフィルターを操作できることが判明しました。攻撃者は悪意あるWebサイトを通じて、被害者のGmailに自動転送フィルターを設定し、すべての受信メールを攻撃者のメールアドレスに転送させることが可能でした。
この攻撃により、被害者のメール内容がすべて攻撃者に漏洩するだけでなく、パスワードリセットメールの傍受によって他のオンラインアカウントの乗っ取りにもつながるリスクがありました。Googleはこの脆弱性を修正し、その後Gmailのセキュリティ対策を大幅に強化しました。
📋 ING Direct バンキングCSRF(2008年)
オランダの大手銀行ING Direct(現ING Bank)のオンラインバンキングシステムにCSRF脆弱性が発見されました。攻撃者は悪意あるWebページを通じて、被害者のログイン中のセッションを利用して口座間の送金を実行できる状態でした。
この脆弱性を悪用すると、被害者が銀行サイトにログインした状態で攻撃者のページを閲覧するだけで、被害者の口座から攻撃者の口座へ資金を送金するリクエストが送信されます。金融機関のWebアプリケーションにおけるCSRF対策の重要性を示す代表的な事例であり、以降の金融規制においてCSRF対策が必須要件として盛り込まれるきっかけとなりました。