この文書は2016年以降更新されていません
クロスサイトリクエストフォージェリ (CSRF) の防止策に関するチートシート
最終改訂日 (yy/mm/dd):2015/12/08 はじめにクロスサイトリクエストフォージェリ (CSRF) は攻撃の一種であり、悪意のある Web サイト、電子メール、ブログ、インスタントメッセージ、またはプログラムを使用して、ユーザーが現在認証されている信頼されたサイト上で、ユーザーの Web ブラウザーに意図しないアクションを実行させます。クロスサイトリクエストフォージェリ攻撃が成功した場合、影響を受けるのは脆弱性のあるアプリケーションによって露出される機能に限られています。たとえば、この攻撃により、送金処理、パスワード変更、ユーザーコンテキストを使用した物品の購入などが行われることがあります。実際、攻撃者は CSRF 攻撃を使用して、ターゲットのシステムにターゲットのブラウザー経由で機能 (送金処理、フォーム送信など) を実行させますが、少なくとも、承認されていない機能の実行が完了するまで、標的にされたユーザーは事態に気づきません。 CSRF 攻撃が成功した場合の影響は、被害者の役割によって大きく異なります。通常のユーザーをターゲットにした場合、CSRF 攻撃が成功すると、エンドユーザーのデータと関連する機能に危害を与える可能性があります。ターゲットにされたエンドユーザーが管理者アカウントの場合、CSRF 攻撃は Web アプリケーション全体に危害を与える可能性があります。攻撃される可能性が高いサイトは、コミュニティ Web サイト (ソーシャルネットワーキング、電子メール) や、高額のアカウントが関連するサイト (銀行、株式売買、請求書支払いサービス) です。強力な暗号化 (HTTPS) を使用している Web サイトに ユーザーがログインした場合でも、この攻撃が起きる可能性があります。ソーシャルエンジニアリングを利用して、攻撃者は悪意のある HTML または JavaScript コードを電子メールまたは Web サイトに埋め込み、「特定のタスクを実行させる URL」 にアクセスさせます。その結果、ユーザーの認識の有無に関係なく、直接またはクロスサイトスクリプティングの脆弱性を利用して(Samy MySpace Worm など)、タスクが実行されます。 CSRF の詳細については、「Cross-Site Request Forgery (CSRF)」ページを参照してください。 クロスサイトスクリプティング (XSS) 脆弱性の防止クロスサイトスクリプティングがなくても、CSRF は機能します。ただし、クロスサイトスクリプティング脆弱性が使用されると、トークン、Cookie の二重送信、Referer ヘッダおよびOrigin ヘッダにもとづくCSRF の防御が無効になる可能性があります。これは、XSS ペイロードが XMLHttpRequest を使用して簡単にサイト上のページを読み込み、生成されたトークンを応答から取得して、そのトークンを偽造したリクエストに含めることができるからです。この技術は、2005 年に MySpace (Samy) ワームが MySpace のCSRF 対策機能をかいくぐってワームを増殖させた方法そのものです。XSS は、チャレンジレスポンスの防御 (Captcha、再認証、ワンタイムパスワードなど) を無効にすることができません。CSRF 防御が回避されないようにするには、XSS 脆弱性が存在しないことが必須になります。XSS 脆弱性を防止する方法の詳細なガイダンスについては、「XSS Prevention Cheat Sheet」を参照してください。 機能しない防止法シークレットクッキーの使用すべての Cookie は (たとえシークレットのものでも)、あらゆるリクエストで送信されることに注意してください。エンドユーザーがだまされてリクエストを送信したのかどうかに関係なく、すべての認証トークンが送信されます。さらに、アプリケーションコンテナーは単純にセッション識別子を使用して、リクエストを特定のセッションオブジェクトに関連付けます。セッション識別子の有無を調べるだけでは、エンドユーザーがリクエストの送信を意図していたかどうかを検証できません。 POST リクエストのみの受け入れアプリケーションは、ビジネスロジックを実行するための POST リクエストのみを受け入れるように開発できます。攻撃者が悪意のあるリンクを作成できなければ CSRF 攻撃は実行できない、というのは誤った認識です。残念ながら、この考え方は正しくありません。攻撃者が被害者をだまして、偽造された POST リクエストを送信させる方法は数多くあります(例えば、攻撃者の Web サイトに、非表示の値を含む単純なフォームを置いてアクセスさせるなど)。しかも、このフォームは JavaScript を使用して自動的にトリガさせることも、フォームが何か別のことをすると思っている被害者にトリガさせることもできます。 マルチステップトランザクションマルチステップトランザクションでは、CSRF を十分に防ぐことはできません。完了したトランザクションの各ステップについて予測や推測ができれば、CSRF は可能になります。 URL の書き換え攻撃者が被害者のセッション ID を推測できないため、これは有効な CSRF 対策技法だと思われるかもしれません。しかし、ユーザーの資格情報が URL で露出します。 一般的な推奨事項:同期トークンパターン"透過的でわかりやすい" CSRF ソリューションを促進するために、開発者は 同期トークンパターン (http://www.corej2eepatterns.com/Design/PresoDesign.htm) を使用することをお勧めします。同期トークンパターンは、ユーザーの現在のセッションと関連するランダムな "チャレンジ" トークンを生成するよう要求します。これらのチャレンジトークンは、機密に関わるサーバー側の操作に関連する、HTML のフォームとリンクに挿入されます。ユーザーがこれらの機密に関わる操作を実行しようとする場合、このチャレンジトークンが HTTP リクエストに含まれている必要があります。すると、サーバーアプリケーションは、このトークンの存在と正確性を検証する責任を負います。各リクエストにチャレンジトークンを含めることによって、開発者は、ユーザーが実際に希望するリクエストを送信するつもりなのかを検証するための、強力なコントロールを持ちます。要求されたセキュリティトークンを機密に関わるビジネス機能と関連する HTTP リクエストに含めることは、CSRF 攻撃の軽減に役立ちます。攻略行為を成功させるには、攻撃者がターゲット被害者のセッションでランダムに生成されるトークンを知っていることが前提だからです。すなわち、攻撃者はターゲット被害者のセッション識別子を推測できる必要があります。次に、リクエストにチャレンジトークンを組み込むための一般的な方法について概説します。 Web アプリケーションは、リクエストを作成 (ユーザーが送信またはクリックするとリクエストを発生させるリンクまたはフォームを生成) するときに "CSRFToken" などの一般的な名前の付いた非表示の入力パラメーターを加えておきます。このトークンの値は、攻撃者が推測できないように、ランダムに生成される必要があります。Java アプリケーションの場合には、十分な長さのランダムなトークンを生成するために java.security.SecureRandom クラスを利用することを検討してください。または、256 ビットのハッシュ値を BASE64 でエンコードする方法もあります 。ただしこの方法を使う場合は、ランダムなトークンを生成するためにハッシュされるデータを確実にランダムで一意のものにする必要があります。 <form action="/transfer.do" method="post"> <input type="hidden" name="CSRFToken" value="OWY4NmQwODE4ODRjN2Q2NTlhMmZlYWE... wYzU1YWQwMTVhM2JmNGYxYjJiMGI4MjJjZDE1ZDZ... MGYwMGEwOA=="> … </form> 通常、開発者は現在のセッションに対して、このトークンを 1 回だけ生成する必要があります。このトークンを最初に生成したら、値をセッションに保存します。この値はセッションが期限切れになるまで、後続の各リクエストに利用されます。エンドユーザーがリクエストを送信すると、サーバー側のコンポーネントはセッション内に保存されているトークンと比較して、リクエスト内のトークンの存在と有効性を検証する必要があります。リクエスト内にトークンが見当たらない場合や、提供される値がセッションに保存されている値と一致しない場合は、リクエストの処理を中止し、トークンをリセットして CSRF 攻撃進行中の可能性ありというイベントを記録する必要があります。 ここで提案した設計のセキュリティを強化するために、CSRF トークンのパラメーター名と各リクエストの値をランダム化することを検討してください。このアプローチを実装すると、セッション単位のトークンではなく、リクエスト単位のトークンが生成されます。ただし、これは使い勝手の問題につながる可能性がある点に注意してください。たとえば、ブラウザーの [戻る] ボタンの機能は頻繁に機能しなくなります。これは前のページに含まれているトークンが、すでに無効になっている場合があるためです。前のページとの対話により、サーバーでは CSRF 攻撃を受けたという誤ったセキュリティイベントが引き起こされます。どのような アプローチを採用するにしても、 認証された後のセッション識別子を保護する場合と同じ方法で (TLS の使用など)、CSRF トークンを保護することをお勧めします。 URL でのトークンの開示このコントロールの実装の多くでは、GET (URL) リクエストと POST リクエストにチャレンジトークンを含めます。ページなどの一般的なデザインパターンに埋め込まれたリンクから機密に関わるサーバー側の操作が呼び出されたときに、これを実装するのが一般的です。これらデザインパターンは、CSRF の知識も CSRF 対策のデザイン戦略の理解もないまま実装されることがよくあります。このコントロールは CSRF 攻撃のリスクを軽減するために役立ちますが、一意のセッション単位トークンが GET リクエストで露呈します。GET リクエストの CSRF のトークンは、ブラウザーの履歴、HTTP ログファイル、必ず HTTP リクエストの最初の行を記録するネットワークアプライアンス、および保護されたサイトが外部サイトにリンクする場合の Referer ヘッダーなど、いくつかの場所でリークされる可能性があります。 後者の場合 (リンクされたサイトで Referer ヘッダーが解析されることによる CSRF トークンのリーク)、リンクされたサイトはいとも簡単に保護されたサイトに CSRF 攻撃を開始できます。Referer ヘッダーからサイトと CSRF トークンが分かる ので、攻撃者はきわめて効果的に攻撃を仕掛けることができます。攻撃は JavaScript だけで 実行できます。サイトの HTML にスクリプトタグを追加するだけで (攻撃者が用意した 悪意のあるサイト上に追加するか、ハッキングされたサイト上に追加することで)、攻撃を起動できます。さらに、HTTPS コンテキストからの HTTPS リクエストは (HTTPS からの HTTP リクエストとは対照的に) Referer ヘッダーを削除しないため 、HTTPS アプリケーションでは、Referer を経由した CSRF トークンのリークが依然として発生する可能性があります。 理想的なソリューションは、POST リクエストにのみ CSRF トークンが含まれるようにし、サーバー側で状態変化を起こすようなアクションは POST リクエストでのみ可能とするよう修正することです。実は、これは RFC 2616 が GET リクエストに要求していることです。機密に関わるサーバー側のアクションが POST リクエストへの応答以外にないことが保証されれば、トークンを GET リクエストに含める必要はありません。 しかし、ほとんどの JavaEE Web アプリケーションでは、リクエストから HTTP パラメーターを取得する際に HTTP メソッドのスコーピングを使用することは滅多にありません。"HttpServletRequest.getParameter" の呼び出しは、リクエストが GET メソッドと POST メソッドどちらを使ったものであっても、パラメーター値を返します。これは、HTTP メソッドのスコーピングを実施できないというわけではありません。開発者が HttpServlet クラスの doPost() を明示的にオーバーライドしたり、Spring の AbstractFormController クラスのようなフレームワーク固有の機能を活用することで実施できます。 これらの場合、既存アプリケーションをこのパターンに合わせて改修 しようとすると、開発に膨大な時間とコストが必要になり、一時的措置として CSRF トークンを URL に含めて渡す方がましかもしれません。アプリケーションが HTTP GET リクエストと POST リクエスト に適切に応答するように修正したら、GET リクエストの CSRF トークンはオフにする必要があります。 ViewState (ASP.NET)ASP.NET には、ViewState と呼ばれる機能があります。ViewState はサーバーに送信されたときのページの状態を示します。状態は、 |