多くのチュートリアルとガイドで、リクエストごとにCSRFトークンを更新する必要があることがわかりました。私の質問は、なぜこれをしなければならないのですか?セッションごとに1つのCSRFトークンは、リクエストごとに1つ生成し、リクエストされたものを追跡するよりもはるかに簡単ではありませんか?
リクエストごとにトークンを生成しても、セッションごとのトークンがすでに行っているよりもセキュリティが向上するようには見えません。唯一の議論はXSS保護であるようですが、XSSの脆弱性がある場合、スクリプトはとにかく新しいトークンを読み取ることができるため、これは当てはまりません。
リクエストごとに新しいトークンを生成するメリットは何ですか?
すでに説明した理由により、リクエストごとに新しいトークンを生成する必要はありません。セキュリティ上の利点はほとんどなく、使いやすさの点でコストがかかります。一度に有効なトークンが1つだけの場合、ユーザーはWebアプリケーションを正常にナビゲートできなくなります。たとえば、「戻る」ボタンを押して新しい値でフォームを送信すると、送信は失敗し、おそらく敵対的なエラーメッセージが表示されます。 2番目のタブでリソースを開こうとすると、一方または両方のタブでセッションがランダムに中断します。この無意味な要件を満たすことは、通常、アプリケーションの使いやすさを改善する価値はありません。
ただしis新しいCSRFトークンを発行する価値がある場所の1つ:セッション内のプリンシパルの変更時。つまり、主にログイン時です。これは、CSRF攻撃の可能性につながるセッション固定攻撃を防ぐためです。
例:攻撃者がサイトにアクセスし、新しいセッションを生成します。彼らはセッションIDを取得して被害者のブラウザーに挿入し(たとえば、脆弱なネイバードメインからCookieを書き込むか、jsessionid URLなどの別の脆弱性を使用して)、被害者のブラウザーのフォームにCSRFトークンを挿入します。彼らは、被害者がそのフォームでログインするのを待ってから、別のフォーム投稿を使用して、被害者にまだ有効なCSRFトークンでアクションを実行させます。
これを防ぐには、CSRFトークンを無効にして、セッションIDに対してすでに行っている場所(ログインなど)で新しいトークンを発行して、セッション固定攻撃を防ぎます。
概要標準的なアドバイスは、要求ごとに一意の一意のCSRFトークンを使用することです。どうして?リクエストごとのトークンは、セッションごとのトークンよりも、特定の種類の実装エラーに対して少し回復力があるためです。これにより、リクエストごとのトークンが、間違いなく新しいWebアプリケーション開発に最適な選択肢になります。また、セキュリティ監査人がリクエストごとのCSRFトークンを使用することに煩わされることはありません。
あなたがウェブアプリケーション開発者なら、これがあなたが知る必要があるすべてであり、ここで読むのをやめることができます。しかし、このアドバイスの背後にある詳細な根拠について疑問に思っている、またはセッションごとのトークンを使用する場合のリスクがどれほど大きいか疑問に思っているセキュリティの専門家であれば、読んでください...
少し深く掘り下げます。真実は、Webサイトに他の脆弱性がない場合、セッションごとに1つのCSRFトークンで問題ないということです。リクエストごとに新しいCSRFトークンを生成する必要がある必要がある理由はありません。
これは、CSRFを防御する別の合理的な方法はCookieの二重送信を使用することであると評判の高いセキュリティ専門家も見つけるという事実によって示されます。つまり、ハッシュのハッシュを計算するクライアント側のJavascriptを使用します。セッションCookieを使用して、それを各POST要求に追加し、ハッシュをCSRFトークンとして扱います。これにより、本質的に、セッション全体で同じCSRFトークンがオンザフライで生成されます。 。
もちろん、一部の人々がすべてのリクエストに対して新しいCSRFトークンを生成することを推奨する理由を私は知っています。彼らは、あなたのWebサイトにXSSの脆弱性がある場合、セッションごとに単一のCSRFトークンを使用すると、XSSを使用してCSRFトークンを回復するのが簡単になりますが、リクエストごとに新しいCSRFトークンを生成すると、 CSRFトークンを回復するには、さらに多くの作業が必要になります。個人的には、これはひどく説得力のある議論だとは思いません。サイトにXSSの脆弱性がある場合、リクエストごとに新しいCSRFトークンを生成しても、悪意のあるJavaScriptを数行追加するだけで、CSRFトークンを回復できます。どちらの方法でも、サイトにXSSの脆弱性があり、深刻で知識豊富な攻撃者に直面した場合、CSRFトークンをどのように生成しても、セキュリティを保証することは困難です。
全体として、リクエストごとに新しいCSRFトークンを生成しても問題はありません。そして、セキュリティ監査人を背負わせるために、そのようにするのが良いかもしれません。しかし、セッション全体で単一のCSRFトークンを使用するレガシーアプリケーションがすでにある場合、お金を費やしてそれを変換し、各リクエストの新しいCSRFトークンを生成することは、おそらく私の優先リストでは高すぎないでしょう:そのお金と開発者のエネルギーの他の用途を見つけて、セキュリティをさらに向上させることができます。
XSSを使用してCSRFトークンを読み取ることができます。それが単一の送信トークンであっても、それは子供の遊びです。この単一の送信トークンの推奨は、CSRFを理解していない人からのものである可能性があります。
「単一の送信トークン」を使用する唯一の理由は、ユーザーが誤って送信を2回クリックしないようにする場合です。これは、ユーザーが「チェックアウト」を2回クリックして誤ってお客様に2回請求することを防ぐために使用します。
CAPTCHAまたはユーザーに現在のパスワードを要求することは、XSSで回避できないcsrf対策として使用できます。
CSRF防止に関するチートシート を読むことをお勧めします。
トークンがセッション全体で同じである場合、攻撃者が1つのページからトークンをリークし、それを別のアクションに使用する可能性があります。
たとえば、iframeを使用してページをロードし、XSS脆弱性を使用してトークンを抽出できます。そこから、そのトークンを使用してパスワード変更フォームを送信できます
セッション全体のトークンの代わりに要求ごとのトークンを使用すると、さらに難しくなりますが、CSRFを防ぐことはできません。攻撃者は、XSSを利用してページからトークンを読み取り、発射するだけです。ただし、トークンがその個別のページに制限されるのではなくグローバルである場合、攻撃者は任意のページを対象としてトークンを盗むことができます。リクエストごとに個別のトークンを使用すると、これがはるかに困難になります。
他の回答に加えて、サーバーが BREACH攻撃 の影響を受けやすい場合は、トークンも更新することをお勧めします。
これには、次の3つの条件が必要です。
- HTTPレベルの圧縮を使用するサーバーから提供される
- ユーザー入力をHTTP応答本文に反映する
- HTTP応答本文にシークレット(CSRFトークンなど)を反映する
BREACHを軽減するには、フォームをロードする以前のトークンをすべて無効にするGETリクエストでCSRFトークンを更新する必要があります。このように、ページ内のトークンを検出するための追加のリクエストを作成するMITM(Man-In-The-Middle)は、毎回異なるトークンを取得します。これは、実際のユーザーがMITM状況でフォームを送信できないことを意味します。
もちろん、他の2つの条件も満たす必要があります。セッションごとにCSRFトークンを維持し、フォームを提供するページに対してHTTPレベルの圧縮を無効にする方がおそらく簡単でしょう。
あまり知られていない事実ですが、通常の文字列比較はタイミング攻撃に対して脆弱です( これなど 。長いストーリーの短い通常の文字列比較演算(==
または===
)は、2つの文字列を左から右に1文字ずつ比較し、両方の文字列の特定の位置で等しくない文字が見つかるとfalseを返します。これは 検出可能であることが証明されている であったタイミングにわずかな違いを与えます。
タイミング攻撃を使用して、各位置のすべての可能な文字を試すことにより、実際のトークンが何であるかを理解することが可能です。トークンを含むリクエストが送信されるたびに新しいトークンを作成することにより、この攻撃を防ぐことができます。
もちろん、これは、invalidトークンが送信された場合にトークンを再作成する場合にのみ機能します。これは望ましくない場合があります。したがって、 これのような時間に依存しない文字列比較関数 を使用してこれを修正した方がよいでしょう。
リクエストごとにCSRFトークンを変更する理由の1つは、トークンの圧縮リークを軽減するためです。つまり、攻撃者のEveが、ページが圧縮されて送信されるトークンを含むページにデータを挿入できる場合、Eveは、文字列の最初の文字を推測して、ページの小さなデータセットを受け取り、推測したことがわかります次の文字に進みます。
これはタイミング攻撃に似ています。
現時点では、HTTPヘッダーでのみ送信されるトークンを変更する理由はありません(私が知っていることです)。
もう1つの方法は、失敗した要求が検出されるとすぐにトークンを変更することですが、これにより、ユーザーがフォームを送信できないという問題が発生する可能性があります。