CSRF攻撃とは何ですか?
古典的なリソースに対するCSRF攻撃のアイデアに精通することができます。
SOへの回答からの抜粋:
CSRFの理由は、アクションがユーザーによって明示的に実行されたか( たとえば、フォーム上のボタンをクリックするか、リンクをたどるなど )、ユーザーがこのアクションを誤って実行したかどうか( たとえば、リソースでbad.com
したとき )を区別する方法をブラウザーが理解しないという事実にありますユーザーが既にgood.com
ログインしている間にリクエストがgood.com/some_action
に送信されました )。
それから身を守る方法は?
CSRF攻撃から保護する効果的で一般的に受け入れられた方法はトークンです。 トークンとは、サーバーがクライアントに送信するランダムなバイトセットを意味し、クライアントはサーバーに戻ります。
保護は、サーバーが生成したトークンとユーザーが送信したトークンをチェックすることになります。
そして、実際には、何を保護するのですか?
RFC7231標準に従ってWebサービスを作成する場合、 GET
、 HEAD
、 OPTIONS
およびTRACE
メソッドは安全です。これらは情報の受信のみを目的としており、サーバーの状態を変更すべきではありません。
したがって、 POST
、 PUT
、 DELETE
、 PATCH
安全でないメソッドを保護する必要があります。
Yandexの記事がHabrahabrに公開されました。これは、標準に従って、サービスを作成する必要がある理由を説明しています 。
トークンの要件:
- 各操作の一意のトークン
- 一度だけ有効
- それは選択に耐えるサイズを持っています
- 暗号的に堅牢な擬似乱数ジェネレーターによって生成
- 寿命が限られている
最初のMeetUp PDUGで Timur Yunusov( 銀行セキュリティ責任者
Positive Technologiesシステム ) は 、まさにそのような要件がCSRFトークンに課されている理由と、それらを無視する脅威となるものを説明しました。
Webサービスと環境の要件:
XSS脆弱性の欠如
攻撃者によって導入されたスクリプトには、ユーザーに代わってサーバーにリクエストを送信し、障害なくそれを読み取る機能があります。
したがって、XSSの脆弱性を使用して現在のトークンを取得できます。
クライアントマシンにマルウェアはありません
攻撃者がクライアントのマシンでソフトウェアを実行できる場合、攻撃者はブラウザで利用可能なデータを取得できます。
セキュリティ方法
トークンを使用してWebサービスをCSRF攻撃から保護するには、3つの方法があります。
- シンクロナイザートークン ( Statefull )
- 二重送信Cookie ( ステートレス )
- 暗号化されたトークン ( ステートレス )
シンクロナイザートークン
どこでも使用される単純なアプローチ。 サーバー側にトークンストレージが必要です。
要点:
サーバー側でセッションが開始されると、トークンが生成されます。
トークンはセッションデータストアに配置されます ( つまり、後で検証するためにサーバー側に保存されます )
( セッションを開始した )要求への応答で、トークンがクライアントに返されます。
サーバーでレンダリングが行われる場合、トークンはフォームフィールドの1つなどのHTML内、または
<meta>
タグ内に返されます。
JSアプリケーションに対して応答が返された場合、トークンをヘッダーに渡すことができます( 多くの場合、
X-CSRF-Token
これに使用されます )
後続のリクエストでは、クライアントは検証のためにサーバーにトークンを渡す必要があります。
サーバーがコンテンツをレンダリングするとき、フォームdataのPOST内でトークンを返すのが慣例です。
JSアプリケーションは通常、トークンを含むヘッダー (
X-CSRF-Token
)でXHR要求を送信します。
安全でないメソッド(
POST
、PUT
、DELETE
、PATCH
)がリクエストを受信すると、サーバーはセッションデータとクライアントが送信したトークンからトークンのIDを確認する必要があります 。
両方のトークンが一致する場合、リクエストはCSRF攻撃を受けませんでした。それ以外の場合、イベントをログに記録し、リクエストを拒否します。
出力には次のものがあります。
優れたCSRF保護
トークンは、セッションが再作成されたときにのみ更新されます。これは、セッションの有効期限が切れたときに発生します
1つのセッションの存続期間中、すべてのアクションは1つのトークンによってチェックされます 。
トークンリークが発生した場合、攻撃者は任意の要求 に対して長時間にわたって CSRF攻撃を実行できます。 そして、これは良くありません。
ブラウザでのマルチタブの無料サポート。
トークンは要求が完了した後は無効になりません。これにより、開発者は常に1つのトークンがあるため、ブラウザーの異なるタブでトークンを同期することを心配する必要がなくなります。
二重送信Cookie
このアプローチでは 、サーバー側のデータストレージは必要ありません 。つまり、 ステートレスです。 Webサービスを迅速かつ効率的に水平方向に拡張できるようにする場合に使用します。
アイデアは、Cookieと、応答パラメーター ( ヘッダーまたはHTML内 )の2つの方法でトークンをクライアントに提供することです。
要点:
クライアントから要求されると、サーバー側でトークンが生成されます。 応答では、トークン(たとえば
X-CSRF-Token
)と応答パラメーターの1つ ( ヘッダーまたはHTML内 )でトークンが返されます 。
後続のリクエストでは、クライアントは以前に受信した両方のトークンを提供する必要があります。 1つはCookieとして、もう1つはヘッダーまたはフォームdataのPOST内にあります 。
安全でないメソッド(
POST
、PUT
、DELETE
、PATCH
)による要求の受信時に、サーバーは、Cookieトークンとクライアントが明示的に送信したトークンのID を検証する必要があります 。
両方のトークンが一致する場合、リクエストはCSRF攻撃を受けませんでした。それ以外の場合、イベントをログに記録し、リクエストを拒否します。
出力には次のものがあります。
ステートレスCSRF保護。
サブドメインは、明示的に禁止しない限り(つまり、Cookieが
.site.ru
に設定されている場合、a.site.ru
とb.site.ru
両方が読み取ることができます)、メインドメインのCookieを読み取ることができます。
したがって、サービスが第3レベルのドメインで利用可能であり、攻撃者が自分のリソースを第2レベルのドメインに登録する機会がある場合、ドメインに明示的にCookieを設定します。
- ニュアンスは実装に依存
暗号化されたトークン
Double Submitと同様に、 ステートレスアプローチです。 主な理由は、信頼性の高いアルゴリズムでデータを暗号化してクライアントに送信すると、クライアントはキーを知らないと偽造できないということです。 このアプローチでは、Cookieを使用する必要はありません。 トークンは、応答パラメーターでのみクライアントに送信されます。
このアプローチでは、 トークンはキーで暗号化された事実です。 最低限必要な事実は、 ユーザーIDとトークン生成時間のタイムスタンプです。 キーはクライアントに知られるべきではありません。
要点:
クライアントから要求されると、サーバー側でトークンが生成されます。
トークン生成は、将来トークンを検証するために必要なファクトを暗号化することで構成されます。
最低限必要な事実は、 ユーザーIDとタイムスタンプです。 応答では、トークンは応答パラメーターの1つ ( ヘッダー内またはHTML内 )で返され ます 。
後続のリクエストでは、クライアントは以前に受信したトークンを提供する義務があります。
安全でないメソッド(
POST
、PUT
、DELETE
、PATCH
)がリクエストを受信すると、サーバーはクライアントから受信したトークンを検証する必要があります。
トークンの検証は、その解読と、解読後に得られた事実と実際の事実の比較から成ります。 ( タイムスタンプチェックは、トークンの有効期間を制限するために必要です)
復号化できなかった、または事実が一致しない場合、リクエストはCSRF攻撃を受けたと見なされます。
出力には次のものがあります。
ステートレスCSRF保護
Cookieにデータを保存する必要はありません
- サブドメインには微妙な違いはありません。
実装について
このリクエストがどのHTTPメソッドおよび目的のために行われたとしても、リクエストごとに新しいトークンを生成しましょう。
したがって、常に変化するトークンを取得します。
もちろん、マルチタブ作業を整理するという疑問が生じます。
タブ間のトークン同期は、 localStorageとそのStorageEventを使用して実装できます
トークンを含むCookie の有効期間を妥当な値に制限します。 たとえば、30分。
JSからCookieを使用不可にする( HTTPOnly = trueに設定)
TLSを使用してMITMを防止する
この場合、HTTPS経由でのみCookieを送信します( Secure = trueに設定)
トークンのサイズは少なくとも32バイトです。
暗号的に堅牢な擬似乱数ジェネレータを使用してトークンを生成します。
これを行うには、システム関数を使用できます。
Linux => getrandom(2) , /dev/urandom OpenBSD => getentropy(2) Unix-like => /dev/urandom Windows => CryptGenRandom API
他に何を知る必要がありますか?
トークンは、CSRFに対する必須の保護です。
チェックしてください。ただし、
X-Requested-With: XMLHttpRequest
のみに依存しないでくださいX-Requested-With: XMLHttpRequest
チェックするが、ヘッダーのみに依存しない:
Host
、Origin
、Referer
URLでトークンを渡さないでください
- すべてのリクエストを保護します。
同じサイト
現在、Cookie(執筆時点での最新バージョン)の「同じサイト」属性の仕様に取り組んでいます。
この属性により、開発者は、Cookieが設定されているサイト以外のサイトからリクエストが送信された場合、Cookieを送信する必要がないことを明示的に示すことができます。 それは、追加のツールを使用せずに、CSRFからリソースを保護する機会があることを意味します。
Chromeブラウザはすでにこの機能をサポートしています。
Stack Exchangeで利用可能な方法と理由に関する詳細情報を入手できます。