CSRF対策のトークン実装方法|クロスサイトリクエストフォージェリ防止
2023年、ある地方自治体のWebサイトで不正な住民情報の変更が発生しました。原因はCSRF(クロスサイトリクエストフォージェリ)攻撃への対策不足でした。「うちのシステムは大丈夫だろうか」と不安に感じている開発担当者の方も多いのではないでしょうか。
2023年、ある地方自治体のWebサイトで不正な住民情報の変更が発生しました。原因はCSRF(クロスサイトリクエストフォージェリ)攻撃への対策不足でした。「うちのシステムは大丈夫だろうか」と不安に感じている開発担当者の方も多いのではないでしょうか。
CSRF攻撃は、利用者が気づかないうちに不正なリクエストを送信させる手法です。IPAの「安全なウェブサイトの作り方」でも重要な対策項目として挙げられており、中小企業のWebアプリケーションでも被害が報告されています。
本記事では、CSRF攻撃の仕組みから、標準的な対策手法であるCSRFトークンの実装方法、さらに検証手順まで詳しく解説します。フレームワーク別の具体例も紹介しますので、自社システムへの適用イメージを掴んでいただけます。
CSRF(クロスサイトリクエストフォージェリ)攻撃とは何か
CSRF攻撃とは、利用者が意図しない操作を強制的に実行させる攻撃手法です。攻撃者が用意した罠サイトを訪問しただけで、ログイン中の別サイトで不正な操作が実行されてしまう危険性があります。
CSRF攻撃の仕組みと被害例
CSRF攻撃は以下の流れで成立します。
- 利用者が銀行サイトなどにログインした状態でブラウザを開いている
- 攻撃者が用意した罠サイトや罠メールのリンクをクリック
- 裏側で銀行サイトへの不正なリクエストが自動送信される
- ブラウザに保存されたセッション情報が自動的に付与される
- 銀行サイトは正規の利用者からのリクエストと判断して処理を実行
実際の被害例としては、不正な振込処理の実行、パスワードやメールアドレスの変更、ECサイトでの勝手な購入処理などが報告されています。2022年には国内の大手ECサイトでCSRF脆弱性が発見され、パッチ適用が行われた事例もあります。
なぜCSRF攻撃が成立するのか
CSRF攻撃が成立する根本的な理由は、Webブラウザが自動的にセッション情報を送信する仕組みにあります。
多くのWebアプリケーションは、利用者のログイン状態を維持するためにセッションIDをCookieに保存します。ブラウザは同じドメインへのリクエスト時に、自動的にこのCookieを送信します。この仕組み自体は正常な動作ですが、攻撃者はこれを悪用するのです。
通常のセキュリティ対策である「ログイン認証」や「セッション管理」だけでは、CSRF攻撃を防ぐことはできません。なぜなら、攻撃リクエストには正規の利用者のセッション情報が含まれているため、サーバー側では正規のリクエストと区別できないからです。
CSRF攻撃で起こりうる実被害
CSRF攻撃による被害は、対象システムの機能によって異なりますが、以下のような深刻なケースが考えられます。
- 金融機関のシステム:不正な振込・送金処理の実行
- ECサイト:勝手な商品購入、配送先の変更
- 会員制サイト:パスワード変更による乗っ取り、退会処理
- SNS・掲示板:不正な投稿、フォロー、いいねの実行
- 管理画面:権限変更、データ削除、設定変更
特に管理者権限でログインしている状態で攻撃を受けると、システム全体に影響を及ぼす可能性があります。2021年には、ある企業の社内システムでCSRF攻撃により、管理者アカウントの権限が不正に変更された事例も報告されています。
中小企業が狙われやすい理由
中小企業のWebアプリケーションが狙われやすい理由として、以下の点が挙げられます。
まず、開発時のセキュリティ対策が不十分なケースが多いことです。予算や時間の制約から、機能開発が優先され、セキュリティ対策が後回しになりがちです。実際に、ある調査では中小企業の約60%がCSRF対策を実装していないという結果も出ています。
次に、既存システムの脆弱性が放置されやすい点も挙げられます。数年前に構築したシステムを更新せずに使い続けている場合、当時は問題視されていなかった脆弱性が残っているケースがあります。
さらに、外部に委託して開発したシステムの品質を確認できないという問題もあります。納品されたシステムにCSRF対策が含まれているか、自社で判断できる担当者がいないケースが多いのです。
CSRFトークンによる対策の基本原理
CSRF攻撃への標準的な対策手法が、CSRFトークンを使った検証です。この仕組みを理解することで、自社システムへの実装イメージが掴めます。
CSRFトークンとは何か
CSRFトークンとは、リクエストの正当性を確認するために使用する、推測困難なランダム文字列のことです。具体的には以下のような特徴を持ちます。
- 予測不可能な長い文字列(通常32文字以上)
- フォーム表示時にサーバー側で生成
- セッションと紐付けて保存
- フォーム送信時に一緒に送信される
- 使用後は無効化される(ワンタイム性)
トークンの生成には、暗号学的に安全な乱数生成器が使用されます。PHPであれば「random_bytes()」、Pythonであれば「secrets」モジュールなどが推奨されています。
なぜトークンで防げるのか
CSRFトークンが攻撃を防げる理由は、攻撃者がトークンの値を知ることができない点にあります。
通常のフォーム送信では、以下の流れでトークンが検証されます。
- 利用者がフォーム画面にアクセス
- サーバーがトークンを生成し、フォームに埋め込む
- 同時にトークンをセッションに保存
- 利用者がフォームを送信
- サーバーが送信されたトークンとセッションのトークンを比較
- 一致すれば正規のリクエストと判断
攻撃者は利用者のブラウザに埋め込まれたトークンを取得できないため、正しいトークンを含むリクエストを作成できません。結果として、CSRF攻撃が防止されるのです。
ただし、XSS(クロスサイトスクリプティング)脆弱性が存在する場合、トークンが盗まれる可能性があるため、CSRF対策だけでなく総合的なセキュリティ対策が必要です。
トークンの生成・検証フロー
実際のWebアプリケーションでのトークン処理の全体像を見てみましょう。
【フォーム表示時】
- 利用者がフォーム画面にアクセス
- サーバー側でランダムなトークンを生成
- トークンをセッションに保存
- トークンをHTMLのhidden項目に埋め込み
- フォームを利用者のブラウザに返す
【フォーム送信時】
- 利用者がフォームを送信
- hidden項目のトークンも一緒に送信される
- サーバーが受信したトークンとセッションのトークンを比較
- 一致すればリクエストを処理、不一致ならエラー
- 処理後、トークンを無効化(再利用防止)
この仕組みにより、正規の画面から送信されたリクエストのみが処理されるようになります。攻撃者が用意した罠サイトからのリクエストには正しいトークンが含まれないため、サーバー側で拒否されます。
【専門家解説】トークンの安全性を高める要件
CSRFトークンの安全性を高めるためには、以下の要件を満たすことが重要です。
推測困難性の確保では、最低でも128ビット(16バイト)以上のランダム値を使用します。暗号学的に安全な乱数生成器を使用し、連続して生成されるトークンに規則性がないことが求められます。
適切な有効期限の設定も重要です。トークンには有効期限を設定し、古いトークンは無効化します。一般的には、セッションタイムアウトと同じ期間、または個別のフォーム操作が完了するまでの時間(30分〜2時間程度)が推奨されます。
また、ワンタイム性の実装により、使用済みのトークンは即座に無効化することで、リプレイ攻撃を防ぎます。ただし、ブラウザの「戻る」ボタンでの再送信など、正規の利用者の操作も考慮した設計が必要です。
OWASP(Open Web Application Security Project)のガイドラインでは、これらの要件を満たすトークン実装が推奨されています。
主要フレームワーク別のCSRFトークン実装方法
多くのWebアプリケーションフレームワークには、CSRF対策機能が標準で組み込まれています。ここでは主要なフレームワークでの実装例を紹介します。
PHP(Laravel)での実装例
Laravelでは、CSRF対策が標準で有効化されており、非常に簡単に実装できます。
フォームに以下のディレクティブを追加するだけで、CSRFトークンが自動的に埋め込まれます。
【フォームの記述例】
formタグ内に「@csrf」と記述するだけで、hidden項目としてトークンが生成されます。
サーバー側での検証は、Laravelのミドルウェア「VerifyCsrfToken」が自動的に行います。デフォルトで全てのPOST、PUT、PATCH、DELETEリクエストに対して検証が実行されます。
特定のルートを検証対象から除外したい場合(外部APIからのWebhookなど)は、ミドルウェアの「$except」配列に追加することで対応できます。ただし、安易に除外すると脆弱性につながるため、本当に必要なケースのみに限定することが重要です。
Ruby on Railsでの実装例
Ruby on Railsでも、CSRF対策は標準で組み込まれています。
ApplicationControllerに「protect_from_forgery」メソッドが含まれており、これによりCSRF対策が有効化されます。通常、新規プロジェクト作成時に自動的に設定されています。
フォームヘルパーを使用して作成したフォームには、自動的にCSRFトークンが埋め込まれます。「form_for」や「form_with」といったヘルパーメソッドを使用すれば、開発者が意識することなく対策が実装されます。
JavaScriptからのAjaxリクエストでも対策が必要です。Railsでは、metaタグにトークンが埋め込まれており、JavaScriptから取得してリクエストヘッダーに含めることで対策できます。Rails UJSやTurboを使用している場合は、これらの処理も自動化されています。
JavaScriptフレームワークでのCSRF対策実装
React、Vue.js、AngularなどのSPA(Single Page Application)では、従来のフォーム送信と異なる実装が必要です。
一般的な実装パターンとしては、以下の方法があります。
APIサーバーからトークンを取得する方法では、アプリケーション起動時またはログイン時に専用のAPIエンドポイントからトークンを取得し、以降のリクエストヘッダーに含めて送信します。トークンはlocalStorageではなく、メモリ上に保持することが推奨されます(XSS対策のため)。
Cookie based tokenパターンも広く使用されています。サーバー側でトークンをCookieにセットし(HttpOnly属性なし)、JavaScriptで読み取ってリクエストヘッダーに含める方法です。この方法は、AngularのXSRF-TOKEN/X-XSRF-TOKENパターンとして知られています。
いずれの方法でも、サーバー側でトークンの検証を確実に行うこと、トークンの有効期限を適切に設定することが重要です。
WordPressでのCSRF対策
WordPressでは、「nonce」(ナンス)と呼ばれる仕組みでCSRF対策を実装します。
wp_nonce_field関数を使用することで、フォームにnonceが追加されます。第一引数にはアクション名を指定し、第二引数には項目名を指定します。
検証は、wp_verify_nonce関数またはcheck_admin_referer関数を使用します。フォーム送信時に受け取ったnonceと、期待するアクション名を指定して検証を行います。
WordPressのnonceには有効期限があり、デフォルトで24時間です。この期間を過ぎたnonceは無効となるため、長時間フォームを開いたまま送信するとエラーになる可能性があります。
プラグイン開発やテーマのカスタマイズを行う際は、管理画面のフォームには必ずnonce検証を実装することが重要です。これを怠ると、WordPressサイト全体が脆弱性を抱えることになります。
CSRF対策の検証方法とよくある実装ミス
CSRF対策を実装した後は、正しく機能しているか検証することが重要です。また、よくある実装ミスを知ることで、自社システムの問題点を発見できます。
トークンが正しく機能しているか確認する方法
CSRF対策の動作確認は、以下の手順で行えます。
手動での確認方法としては、まずブラウザの開発者ツールでフォームのHTMLを確認し、CSRFトークンが埋め込まれているか確認します。次に、フォームを送信して正常に処理されることを確認します。その後、ブラウザの開発者ツールでトークンの値を変更してから送信し、エラーとなることを確認します。
自動テストでの確認方法も有効です。多くのフレームワークには、CSRFトークンを含むテストヘルパーが用意されています。例えば、Laravelでは「$this->post()」メソッドが自動的にトークンを付与します。正しいトークンでのリクエストが成功すること、トークンなしまたは不正なトークンでのリクエストが失敗することをテストケースに含めます。
実際の導入事例では、ある製造業の企業が既存の受発注システムにCSRF対策を追加した際、検証作業で以下の問題を発見しました。一部の管理画面でトークン検証が実装されていなかったこと、Ajaxリクエストでトークンが送信されていなかったこと、エラー時の処理が不適切で利用者に分かりにくいメッセージが表示されていたことです。これらの問題を修正することで、安全性と使いやすさの両立を実現できました。
よくある実装ミス4選
CSRF対策でよく見られる実装ミスとして、以下のパターンが挙げられます。
1. トークンを生成したが検証していない
フォームにトークンを埋め込んだものの、サーバー側で検証処理を実装していないケースです。トークンがあるだけでは意味がなく、必ず検証が必要です。
2. GETリクエストで重要な処理を実行している
データの変更や削除などの処理をGETリクエストで実行している場合、CSRF対策が無意味になります。これらの処理は必ずPOST、PUT、DELETEなどのメソッドで実装し、トークン検証を行う必要があります。
3. トークンの有効期限が長すぎる・または無期限
トークンに有効期限を設定していない、または極端に長い期限を設定している場合、セキュリティリスクが高まります。適切な有効期限(30分〜2時間程度)を設定することが推奨されます。
4. Ajaxリクエストでトークンを送信していない
通常のフォーム送信ではトークンを実装したが、JavaScriptからのAjaxリクエストでトークンを送信していないケースです。全てのデータ変更リクエストに対してトークン検証を行う必要があります。
CSRF対策だけでは不十分なケース
CSRFトークンは重要な対策手法ですが、これだけで全てのセキュリティリスクが解消されるわけではありません。
特に注意が必要なのは、XSS(クロスサイトスクリプティング)脆弱性との組み合わせです。XSS脆弱性が存在すると、攻撃者がJavaScriptでトークンを取得できてしまうため、CSRF対策が無効化されます。IPAの「安全なウェブサイトの作り方」でも、CSRF対策とXSS対策の両方を実装することが推奨されています。
また、セッション管理の脆弱性にも注意が必要です。セッションハイジャックやセッション固定攻撃により、攻撃者が利用者のセッションを乗っ取れる状態では、CSRF対策の効果が限定的になります。
さらに、権限管理の不備も重要な問題です。CSRF対策を実装していても、適切な権限チェックがなければ、本来アクセスできない機能を実行される可能性があります。
総合的なセキュリティ対策として、以下の項目を含めて実装することが推奨されます。
- CSRF対策(CSRFトークンの実装)
- XSS対策(入力値の検証とエスケープ処理)
- SQLインジェクション対策(プリペアドステートメントの使用)
- 適切なセッション管理(セッションIDの再生成、タイムアウト設定)
- 権限管理の実装(機能ごとのアクセス制御)
- HTTPS通信の強制(通信内容の暗号化)
【注意】誤った対策事例 - Refererチェックだけでは不十分
一部のシステムでは、HTTPリクエストヘッダーの「Referer」をチェックすることでCSRF対策としているケースがあります。しかし、この方法だけでは十分な対策とは言えません。
Refererには以下の問題があります。
まず、Refererは送信されない場合がある点です。利用者のブラウザ設定やプライバシー保護ツール、HTTPSからHTTPへの遷移などで、Refererが送信されないケースがあります。
次に、Refererは偽装可能という問題もあります。一部の環境では攻撃者がRefererを偽装できる可能性があります。
さらに、正規の利用者のリクエストを誤って拒否するリスクもあります。Refererチェックを厳密にすると、正常な操作が拒否される可能性があります。
OWASP(Open Web Application Security Project)のガイドラインでも、Refererチェックは補助的な対策として位置づけられており、主要な対策としてCSRFトークンの使用が推奨されています。
Refererチェックを実装する場合は、CSRFトークンと組み合わせて多層防御を行うという考え方が適切です。トークン検証が主要な対策で、Refererチェックは追加の安全策として位置づけるべきです。
まとめ
CSRF(クロスサイトリクエストフォージェリ)対策について、攻撃の仕組みからトークンによる実装方法、検証手順まで解説しました。重要なポイントは以下の3つです。
- CSRF攻撃の危険性を理解すること:利用者が意図しない操作を実行させられ、不正送金や情報改ざんなどの被害につながる可能性があります。中小企業のWebアプリケーションでも対策不足により被害が発生している実態があります。
- CSRFトークンが標準的な対策手法であること:推測困難なランダム文字列をリクエストに含めることで、正規のリクエストと攻撃を区別できます。主要なフレームワークには標準機能として組み込まれており、適切に使用すればリスクを大幅に低減できます。
- 実装後の検証と総合的な対策が必要であること:トークンを生成するだけでなく、サーバー側での検証まで含めて対策が完了します。また、XSS対策やセッション管理など、他のセキュリティ対策と組み合わせることで、より安全なシステムを構築できます。
次のステップとしては、自社のWebアプリケーションでCSRF対策が実装されているか確認することをおすすめします。フレームワークを使用している場合は標準機能が有効化されているか、独自開発のシステムの場合はトークン検証が実装されているかをチェックしてください。
自社での実装や検証が難しい場合は、セキュリティ診断サービスの利用や、Webアプリケーションセキュリティの専門家への相談を検討してください。IPAの「安全なウェブサイトの作り方」やOWASPのガイドラインも参考になる情報源です。
関連記事
クリックジャッキング対策のX-Frame-Options設定|UIリダイレクト攻撃防止
自社サイトが気づかないうちに悪意のあるサイトに埋め込まれ、利用者が意図せずボタンをクリックしてしまう。このような「クリックジャッキング攻撃」は、透明なiframeを悪用した巧妙な手口で、SNSでの不正投稿や決済の誤操作など深刻な被害を引き起こします。
コマンドインジェクション対策のサニタイズ方法|OSコマンド実行防止術
企業のWebシステムやサーバーを狙うサイバー攻撃の中でも、特に深刻な被害をもたらすのが「コマンドインジェクション攻撃」です。この攻撃が成功すると、攻撃者がサーバー上で任意のOSコマンドを実行できてしまい、機密情報の漏洩やシステム全体の乗っ取りにつながる可能性があります。
インシデント対応フローの作成方法|セキュリティ事故発生時の行動手順
「サイバー攻撃を受けた」「マルウェアに感染したかもしれない」――そんな緊急事態が起きたとき、御社では誰がどう動くか明確になっているでしょうか。セキュリティインシデントの発生時、事前に対応手順が整備されていないと、初動の遅れから被害が拡大してしまいます。