CSRFトークンとは何ですか?その重要性は何であり、どのように機能しますか?


629

私はアプリケーション(Django、そういうことが起こります)を書いていて、実際に「CSRFトークン」が何であるか、それがどのようにデータを保護するのかを知りたいだけです。CSRFトークンを使用しない場合、投稿データは安全ではありませんか?


13
これは、クロスサイトリクエストフォージェリを防止するための、すべてのフォーム送信および副作用URLにおける秘密のユーザー固有のトークンです。詳細はこちら:en.wikipedia.org/wiki/Cross-site_request_forgery
Robert Harvey

1
質問を保護することと広すぎるので禁止することの間には微妙な境界線があるようです:D
anton1980

2
OWASPクロスサイトリクエストフォージェリ(CSRF)対策虎の巻:「クロスサイトスクリプティングが仕事にCSRFのために必要ではないが、任意のクロスサイトスクリプティングの脆弱性はすべてCSRF軽減手法を打ち負かすために使用することができます[...]。。これは、XSSペイロードがXMLHttpRequest [...]を使用してサイト上の任意のページを単純に読み取ることができるためです
。CSRF

回答:


1497

簡単な言葉でのクロスサイトリクエストフォージェリ(CSRF)

  • 現在オンラインバンキングにログインしているとします。 www.mybank.com
  • からの送金のmybank.com結果、フォームが(概念的に)要求されると想定しますhttp://www.mybank.com/transfer?to=<SomeAccountnumber>;amount=<SomeAmount>。(ログインによって暗示されるため、アカウント番号は必要ありません。)
  • あなたは訪問しwww.cute-cat-pictures.orgない、それは悪質なサイトであることを知って、。
  • そのサイトの所有者が上記のリクエストの形式を知っていて(簡単です!)、ログインしていると正しく推測できる場合mybank.com(ある程度の運が必要です!)、次のようなリクエストをページに含めることができますhttp://www.mybank.com/transfer?to=123456;amount=10000123456ケイマン諸島のアカウントの数はそして10000、あなたが以前あなたが所有して嬉しかったと思っていた金額です)
  • あなたは、その取得したwww.cute-cat-pictures.orgページを、ので、あなたのブラウザはその要求を行います。
  • 銀行はこのリクエストの発信元を認識できません。Webブラウザーはwww.mybank.comCookie とともにリクエストを送信し、完全に正当に見えます。あなたのお金があります!

これは、CSRFトークンのない世界です。

今より良い1用 CSRFトークン

  • 転送要求は、3番目の引数で拡張されますhttp://www.mybank.com/transfer?to=123456;amount=10000;token=31415926535897932384626433832795028841971
  • そのトークンは、mybank.com彼らがあなたにそれを提供するとき、彼ら自身のウェブページに含まれるであろう巨大な、推測することができない乱数です。それは異なる、彼らは誰にも任意のページを提供するたびに。
  • 攻撃者はトークンを推測できず、Webブラウザーにトークンを降伏させることができません(ブラウザーが正しく動作する場合...)。したがって、攻撃者は有効な要求を作成できません。間違ったトークン(またはトークンなし)はによって拒否されwww.mybank.comます。

結果:10000通貨単位を維持します。その一部をウィキペディアに寄付することをお勧めします。

(あなたのマイレージは異なる場合があります。)

読む価値のあるコメントから編集:

HTTPアクセス制御のため、www.cute-cat-pictures.org通常のスクリプトは、アンチCSRFトークンにアクセスできないことに注意してくださいwww.mybank.com。このメモはAccess-Control-Allow-Origin: *、別のWebサイトからAPIを使用できないという理由だけで、それが何であるかわからないまま、すべてのWebサイト応答のヘッダーを不当に送信する一部の人々にとって重要です。


36
そして明らかに、トークンは CSRFトークンと名付けられるのが理想的ですが、名前はおそらくそのままで十分に複雑です。
Lutz Prechelt、2016年

3
@LutzPrecheltありがとうございます。javascriptがブラウザから認証トークンを取得できないのはなぜですか?
BKSpurgeon

72
HTTPアクセス制御のため、www.cute-cat-pictures.org通常のスクリプトは、アンチCSRFトークンにアクセスできないことに注意してくださいwww.mybank.com。このメモはAccess-Control-Allow-Origin: *、別のWebサイトからAPIを使用できないという理由だけで、それが何であるかわからないまま、すべてのWebサイト応答のヘッダーを不当に送信する一部の人々にとって重要です。
SOFe 2016年

9
@AugustinRiedinger攻撃者が自分のコンピューターでWebページを開いた場合-ログインしたユーザーのCookieがないため、対応するcsrfトークンを受け取りません(各csrfトークンは特定のユーザーセッションでのみ有効です)。攻撃者がキュートな猫の写真のWebサイトに配置されたスクリプトを使用して、トークンを含むWebページをユーザーのコンピューターに読み込もうとすると、ブラウザーによりwww.mybank.com(およびトークン)が読み取られなくなります。同じ発信元ポリシー。
マルセル

13
@LutzPrecheltトークンが常に異なるだけでは不十分だと思います。セッションとペアにする必要があり、サーバーは受信したトークンが、サーバーが受信したCookieで識別するセッションに対して生成されたことを確認する必要があります。それ以外の場合、ハッカーは自分でmybankにアクセスして有効なトークンを取得するだけです。したがって、すべてのフォームで新しいトークンを使用する場合は、サーバー上でセッションIDとペアにして保存する必要があります。セッションごとに同じトークンを使用する方がおそらく簡単です。
マルセル

222

はい、投稿データは安全です。しかし、そのデータの起源はそうではありません。このようにして、攻撃者のWebページを閲覧しているときに、誰かがJSを持つユーザーをだましてサイトにログインさせることができます。

それを防ぐために、djangoはcookieとフォームデータの両方でランダムなキーを送信します。次に、ユーザーがPOSTを実行すると、2つのキーが同一であるかどうかが確認されます。ユーザーがだまされた場合、サードパーティのWebサイトがサイトのCookieを取得できないため、認証エラーが発生します。


@DmitryShevchenkoこんにちは、cookie + form-inputのこのメソッドが、サーバー側のリファラーを検証することとどのように異なるのかを理解しようとしていますか?私が見つけたすべての例は、ユーザーをだまして自分のサイトから実際のサイトに投稿させるハッカーに関連しています。
2013年

OK、リファラーが使用されない理由がわかりました。機密情報を保持することがあると考えられるため、多くの場合ブロックされます。企業とそのプロキシは通常、これを行います。ただし、HTTPSを使用すると、ブロックされない可能性が高くなります。
2013年

4
リファラーは簡単に変更できますが、信頼できる情報であるとは言えません。ただし、CSRFトークンはサーバーの秘密鍵を使用して生成され、通常はユーザーに関連付けられます
Dmitry Shevchenko 2013年

1
これがセキュリティ上の脅威である理由がよくわかりません。ユーザーは別のサイトにログインします...しかし、元のサイトにはその情報を取得する方法がありません。正しい?
アーキルフェルナンデス2014

6
たとえば、Facebook.com に " bank.com/transfer?from=x&to=y "の悪意のあるiframeを挿入するとします。あなたがbank.comの顧客であり、Facebookにアクセスすると、そのiframeがcookieを使用して銀行ページをロードし(ブラウザーがそれらを既知のドメインに送信するため)、送金を行います。何も知らずに。
ドミトリー・シェフチェンコ

74

サイトは、フォームページを作成するときに一意のトークンを生成します。このトークンは、サーバーにデータをポスト/取得するために必要です。

トークンはサイトによって生成され、フォームを含むページが生成されたときにのみ提供されるため、他の一部のサイトはフォームを模倣できません。トークンを持たないため、サイトに投稿できません。


10
ユーザーはソース内のトークン出力を取得し、送信されたCookieを取得して、サードパーティのサイトから送信できますか?
Jack Marchetti

9
@JackMarchettiはい。ただし、サードパーティのサイトからフォームを送信するたびに、ページをロードしてトークンを解析する必要があるため、コストがかかります。この攻撃ベクトルに関心がある場合、CSRFトークンは他の形式のセキュリティと理想的に組み合わせる必要があります
tkone

4
私は@JackMarchettiと同じ質問をしますが、明確でないのは-ログインごとにCSRFトークンが変更されるかどうかです。それが同じままである場合、攻撃者が最初にログインしてリクエストトークンを取得し、次にそのトークンを攻撃に挿入するのを防ぐにはどうすればよいですか?
Paul Preibisch 2014

7
@PaulPreibischログインごとではなく、ページを読み込むたびに変更する必要があります。このように、攻撃者はフォームを送信するたびにページをリクエストする必要があります。はるかに困難になります。
tkone 2014年

9
@tkone、それは本当にそれをはるかに難しくするわけではありません。努力と時間の量を2倍にするだけなら。いかなる禁止処理も追加されません。トリックはまた、CSRFトークンをドメイン固有のCookieに関連付け、このCookieをフォームと共に送信することです。Cookieとフォーム投稿データの両方をPOSTリクエストでサーバーに送信する必要があります。この方法では、正当な要求をエミュレートできるようにするために、Cookieハイジャック攻撃が必要になります。
Pedro Cordeiro、2015年

56

Cloud Underブログでは、CSRFトークンについて説明しています。

a.comでホストされている、簡略化されたTwitterのようなWebサイトがあるとします。サインインしているユーザーは、POSTリクエストとしてサーバーに送信され、送信ボタンを押すと公開されるフォームにテキスト(ツイート)を入力できます。サーバー上では、ユーザーは一意のセッションIDを含むCookieによって識別されるため、サーバーはツイートを投稿したユーザーを認識します。

フォームは次のように単純にすることができます。

 <form action="http://a.com/tweet" method="POST">
   <input type="text" name="tweet">
   <input type="submit">
 </form> 

想像してみてください。悪者がこのフォームをコピーして悪意のあるWebサイトに貼り付けたとします(b.comなど)。フォームは引き続き機能します。ユーザーがTwitterにサインインしている限り(つまり、ユーザーがa.comの有効なセッションCookieを持っている場合)、http://a.com/tweetユーザーが送信ボタンをクリックすると、POSTリクエストが送信 され、通常どおり処理されます。

これまでのところ、ユーザーがフォームの正確な機能を認識している限り、これは大きな問題ではありませんが、悪者が次のようにフォームを微調整するとどうなるでしょうか。

 <form action="https://example.com/tweet" method="POST">
   <input type="hidden" name="tweet" value="Buy great products at http://b.com/#iambad">
   <input type="submit" value="Click to win!">
 </form> 

さて、ユーザーの1人が悪者のWebサイトに行き、「クリックして勝つ!」ボタンをクリックすると、フォームがWebサイトに送信され、ユーザーはCookieのセッションIDによって正しく識別され、非表示のツイートが公開されます。

私たちの悪者がさらに悪い場合は、JavaScriptを使用してWebページを開くとすぐに、罪のないユーザーがこのフォームを送信するようにします。これは基本的にクロスサイトリクエストフォージェリです。

フォームはどこからでもどこでも簡単に送信できます。通常、これは一般的な機能ですが、フォームが属するドメインからのみフォームの送信を許可することが重要である場合がさらに多くあります。

WebアプリケーションがPOST要求とGET要求を区別しない場合(たとえば、PHPで$ _POSTではなく$ _REQUESTを使用する場合)は、事態はさらに悪化します。やめろ!データ変更リクエストは簡単に送信できます<img src="http://a.com/tweet?tweet=This+is+really+bad">、悪意のあるWebサイトやメールに埋め込まれて、送信できます。

自分のWebサイトからのみフォームを送信できるようにするにはどうすればよいですか?これがCSRFトークンの出所です。CSRFトークンは、ランダムで推測が難しい文字列です。保護したいフォームのあるページで、サーバーはランダムな文字列、CSRFトークンを生成し、それを非表示フィールドとしてフォームに追加し、セッションに保存するかCookieを設定することによって、何らかの形で記憶します値を含みます。フォームは次のようになります。

    <form action="https://example.com/tweet" method="POST">
      <input type="hidden" name="csrf-token" value="nc98P987bcpncYhoadjoiydc9ajDlcn">
      <input type="text" name="tweet">
      <input type="submit">
    </form> 

ユーザーがフォームを送信すると、サーバーは投稿されたフィールドcsrf-token(名前は関係ありません)の値をサーバーが記憶しているCSRFトークンと比較するだけです。両方の文字列が等しい場合、サーバーはフォームの処理を続行します。それ以外の場合、サーバーはフォームの処理を直ちに停止し、エラーで応答する必要があります。

なぜこれが機能するのですか?上記の例の悪者がCSRFトークンを取得できない理由はいくつかあります。

非表示フィールドの値はユーザーごとに異なるため、静的ソースコードをページから別のWebサイトにコピーしても意味がありません。悪意のあるユーザーのWebサイトが現在のユーザーのCSRFトークンを知らなければ、サーバーは常にPOST要求を拒否します。

悪意のあるユーザーの悪意のあるページは、ユーザーのブラウザーによって別のドメイン(a.comではなくb.com)から読み込まれるため、JavaScriptをコーディングすることはできません。これにより、コンテンツが読み込まれ、ユーザーの現在のCSRFトークンがあなたのウェブサイト。これは、ウェブブラウザがデフォルトでクロスドメインAJAXリクエストを許可していないためです。

ドメインが一致しないため、悪意のあるユーザーはサーバーによって設定されたCookieにもアクセスできません。

クロスサイトリクエストフォージェリから保護する必要があるのはいつですか?上記のようにGET、POST、およびその他のリクエストメソッドを混同しないようにできる場合は、デフォルトですべてのPOSTリクエストを保護することから始めます。

上記で説明したように、標準のHTMLフォームは、これらのメソッドを使用するブラウザから送信できないため、PUTおよびDELETEリクエストを保護する必要はありません。

一方、JavaScriptは実際に、jQueryの$ .ajax()関数を使用するなど、他のタイプの要求を行うことができますが、AJAX要求が機能するためには、ドメインが一致する必要があります(他の方法で明示的にWebサーバーを構成しない限り) 。

これは、POSTリクエストであっても、CSRFトークンをAJAXリクエストに追加する必要がない場合が多いことを意味しますが、実際のP​​OSTリクエストが実際のリクエストである場合は、WebアプリケーションのCSRFチェックのみをバイパスする必要があります。 AJAXリクエスト。これは、AJAXリクエストに通常含まれているX-Requested-Withのようなヘッダーの存在を探すことで実行できます。別のカスタムヘッダーを設定して、サーバー側でその存在を確認することもできます。ブラウザは通常のHTMLフォームの送信(上記を参照)にカスタムヘッダーを追加しないため、安全です。BadGuy氏がこの動作をフォームでシミュレートする機会はありません。

AJAXリクエストに疑問がある場合は、何らかの理由でX-Requested-Withのようなヘッダーを確認できないため、生成されたCSRFトークンをJavaScriptに渡して、AJAXリクエストにトークンを追加します。これにはいくつかの方法があります。通常のHTMLフォームと同じようにペイロードに追加するか、AJAXリクエストにカスタムヘッダーを追加します。サーバーが着信要求でそれを探す場所を認識し、それをセッションまたはcookieから記憶した元の値と比較できる限り、ソートされます。


詳細情報をありがとう。ポスト要求中に、サイトはcsrfトークンをサーバーに送信する必要があるので、クライアントはいつこのcsrfトークンをサーバーに送信しますか?プリフライトオプションをリクエストしている最中ですか?...この部分にelablorateしてください
Smのスリカンス

@ダンb.comが他のサイトa.comのCookieにアクセスできるのはなぜですか?
zakir

8

すべての根幹は、リクエストがサイトの実際のユーザーからのものであることを確認することです。csrfトークンはフォーム用に生成され、ユーザーのセッションに関連付ける必要があります。これは、トークンを検証するサーバーにリクエストを送信するために使用されます。これはcsrfから保護する1つの方法です。別の方法はリファラーヘッダーをチェックすることです。


7
リファラーヘッダーに依存しないでください。簡単に偽造できます。
kag

3
これが正解です。トークンはサーバー上のセッションに関連付けられている必要があります。最も投票された回答が示唆するようなCookie +フォームデータの比較は、完全に間違っています。これらのコンポーネントは両方とも、クライアントが構築するリクエストの一部を形成します。
リー・デイビス

3
実は違う。トークンは、サーバーへの各要求に関連付ける必要があります。それをセッションにのみ関連付けると、誰かがセッションのトークンを盗み、そのトークンを使用してリクエストを送信する危険があります。したがって、最大限の安全性を確保するために、トークンは各HTTP要求に関連付ける必要があります。
chrisl08 2016
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.