web-dev-qa-db-ja.com

Railsの認証トークンを理解する

私はこれまで何度も経験してきたように、RailsのAuthenticity Tokenに関するいくつかの問題に遭遇しています。

しかし、私は本当にこの問題を解決し続けたいだけではありません。本当にAuthenticityトークンを理解したいのですが。さて、私の質問は、このテーマに関する完全な情報源を持っているか、それともここで詳細に説明するのにあなたの時間を費やすだろうか?

931
Ricardo Acras

何が起こるか

ユーザーがフォームを表示してリソースを作成、更新、または破棄すると、Railsアプリはランダムauthenticity_tokenを作成し、このトークンをセッションに保存し、形。ユーザーがフォームを送信すると、Railsはauthenticity_tokenを探し、それをセッションに保存されているものと比較し、一致した場合はリクエストを続行できます。

なぜ起こるか

認証トークンはセッションに保存されるため、クライアントはその値を知ることができません。これにより、ユーザーは、アプリ内でフォームを表示せずにRailsアプリにフォームを送信できなくなります。サービスAを使用していて、サービスにログインし、すべてが大丈夫だと想像してください。ここで、サービスBを使用して、好きな写真を見て、その写真を押して大きなサイズを見ると想像してください。さて、サービスBに悪意のあるコードが存在する場合、サービスA(ログインしている)にリクエストを送信し、http://serviceA.com/close_accountにリクエストを送信してアカウントの削除を要求する場合があります。これは、 CSRF(Cross Site Request Forgery) と呼ばれるものです。

サービスAが認証トークンを使用している場合、サービスBからのリクエストには正しい認証トークンが含まれず、続行が許可されないため、この攻撃ベクトルは適用できなくなります。

APIドキュメント メタタグの詳細を説明します。

CSRF保護は、protect_from_forgeryメソッドを使用してオンになります。このメソッドは、トークンをチェックし、予想と一致しない場合にセッションをリセットします。このメソッドの呼び出しは、デフォルトで新しいRailsアプリケーションに対して生成されます。トークンパラメータには、デフォルトでauthenticity_tokenという名前が付けられます。このトークンの名前と値は、HTMLヘッドにcsrf_meta_tagsを含めることにより、フォームをレンダリングするすべてのレイアウトに追加する必要があります。

Railsは、べき等でないメソッド(POST、PUT/PATCH、およびDELETE)のみを検証することに注意してください。 GETリクエストの認証トークンはチェックされません。どうして? HTTP仕様では、GETリクエストはべき等であり、notサーバーでリソースを作成、変更、または破棄する必要があり、リクエストはi等である必要があるため同じコマンドを複数回実行すると、毎回同じ結果になるはずです。

また、実際の実装は、最初に定義したように少し複雑であり、セキュリティが向上します。 Railsは、すべてのフォームで同じ保存済みトークンを発行しません。また、毎回異なるトークンを生成して保存することもありません。セッションで暗号化ハッシュを生成および保存し、ページがレンダリングされるたびに、保存されたトークンと照合できる新しい暗号化トークンを発行します。 request_forgery_protection.rb を参照してください。

レッスン

authenticity_tokenを使用して、not等でないメソッド(POST、PUT/PATCH、およびDELETE)を保護します。また、サーバー上のリソースを変更する可能性のあるGET要求を許可しないようにしてください。


EDIT:dem等であるGETリクエストに関する @ erturneによるコメント を確認してください。彼は私がここでやったよりも良い方法でそれを説明しています。

1425
Faisal

認証トークンは、フォームがWebサイトから送信されていることをユーザーが認識できるように設計されています。それはあなたのマシンだけが知ることができるユニークな識別子でそれが走るマシンから生成され、クロスサイトリクエストフォージェリ攻撃を防ぐのに役立ちます。

RailsがAJAXスクリプトへのアクセスを拒否するのが困難な場合は、次のようにします。

<%= form_authenticity_token %>

フォームを作成するときに正しいトークンを生成します。

ドキュメント でそれについてもっと読むことができます。

131
Topher Fangio

CSRFとは

認証トークンは、クロスサイトリクエストフォージェリ(CSRF)に対する対策です。 CSRFとは何ですか?

攻撃者がセッショントークンを知らなくても、潜在的にセッションをハイジャックすることができる方法です。

シナリオ

  • 銀行のサイトにアクセスしてログインします。
  • その後、攻撃者のサイトにアクセスします(信頼できない組織からのスポンサー付き広告など)。
  • 攻撃者のページには、銀行の "Transfer Funds"フォームと同じフィールドのフォームがあります。
  • 攻撃者はあなたのアカウント情報を知っており、あなたのアカウントから攻撃者のアカウントにお金を振り込むためのフォームフィールドがあらかじめ入力されています。
  • 攻撃者のページには、銀行にフォームを送信するJavaScriptが含まれています。
  • フォームが送信されると、ブラウザにはセッショントークンを含む銀行サイトのCookieが含まれます。
  • 銀行は攻撃者の口座に送金します。
  • 目に見えないiframeにフォームを含めることができるため、攻撃が発生したことはわかりません。
  • これはクロスサイトリクエストフォージェリ(CSRF)と呼ばれます。

CSRFソリューション

  • サーバーは、サーバー自体から送信されたフォームにマークを付けることができます。
  • すべてのフォームには、隠しフィールドとして追加の認証トークンを含める必要があります。
  • トークンは予測不可能でなければなりません(攻撃者はそれを推測できません)。
  • サーバーはそのページのフォームに有効なトークンを提供します。
  • サーバーはフォームがポストされたときにトークンをチェックし、適切なトークンがないフォームを拒否します。
  • トークン例:サーバの秘密鍵で暗号化されたセッション識別子。
  • Railsは自動的にそのようなトークンを生成します。あらゆる形式のauthenticicity_token入力フィールドを見てください。
81
Rose Perrone

防止されるであろう最小限の攻撃の例

私のウェブサイトでevil.com私はあなたに次のフォームを提出することを納得させます:

<form action="http://bank.com/transfer" method="post">
  <p><input type="hidden" name="to"      value="ciro"></p>
  <p><input type="hidden" name="ammount" value="100"></p>
  <p><button type="submit">CLICK TO GET PRIZE!!!</button></p>
</form>

あなたがセッションクッキーを通してあなたの銀行にログインしているならば、それからクッキーは送られるでしょう、そしてあなたがそれを知らなくても転送はなされるでしょう。

それがCSRFトークンが効力を発揮したことです。

  • フォームを返したGETレスポンスで、Railsは非常に長いランダムな隠しパラメータを送ります。
  • ブラウザがPOSTリクエストをするとき、それはパラメータを一緒に送ります、そしてサーバはそれが一致する場合にのみそれを受け入れます

そのため、本物のブラウザのフォームは次のようになります。

<form action="http://bank.com/transfer" method="post">
  <p><input type="hidden" name="authenticity_token" value="j/DcoJ2VZvr7vdf8CHKsvjdlDbmiizaOb5B8DMALg6s=" ></p>
  <p><input type="hidden" name="to"                 value="ciro"></p>
  <p><input type="hidden" name="ammount"            value="100"></p>
  <p><button type="submit">Send 100$ to Ciro.</button></p>
</form>

したがって、私の攻撃はauthenticity_tokenパラメータを送信していなかったために失敗し、巨大な乱数であるため推測できなかった可能性があります。

この防止技術は シンクロナイザトークンパターン と呼ばれます。

シンクロナイザトークンパターンは、 同一オリジンポリシー のために機能します。evil.comからXHR GETリクエストをあなたの銀行に送信し、その結果を読むことができれば、ただ読むことができるでしょう。トークンを作成して、後で要求を出します。私はこれについてさらに説明しました: https://security.stackexchange.com/a/72569/53321

これやその他のセキュリティ問題については、 OWASPガイド を読むことを強くお勧めします。

Railsがトークンを送信する方法

対象範囲: Rails:csrf_meta_tagの動作方法は?

基本的に:

  • form_tagのようなHTMLヘルパーは、それがGETフォームではない場合、あなたに代わってフォームに隠しフィールドを追加します。

  • AJAXは jquery-ujs によって自動的に処理されます。これは、(デフォルトのテンプレートに存在する)csrf_meta_tagsによってヘッダに追加されたmeta要素からトークンを読み取り、それをすべてのリクエストに追加します。

    また、uJSは、キャッシュされた古いフラグメントのフォームのトークンを更新しようとします。

その他の予防方法

Authenticity TokenはRailsの 防止'クロスサイトリクエストフォージェリ(CSRFまたはXSRF)攻撃' です。

簡単に言うと、WebアプリケーションへのPUT/POST/DELETE(コンテンツを変更できるメソッド)リクエストは、第三者(攻撃者)からではなくクライアントのブラウザから行われるようになっています。クライアント側で作成されたクッキーにアクセスできます。

36
andi

信頼性トークンは、クロスサイトリクエストフォージェリ攻撃(CSRF)を防ぐために使用されます。信頼性トークンを理解するには、まずCSRF攻撃を理解する必要があります。

CSRF

あなたがbank.comの作者であるとします。あなたのサイトには、GETリクエストで他の口座に送金するためのフォームがあります。

enter image description here

ハッカーがHTTPリクエストをサーバーに送信してGET /transfer?amount=$1000000&account-to=999999と言っている可能性があります。

enter image description here

違う。ハッカーの攻撃はうまくいきません。サーバーは基本的に考えるでしょうか?

え?誰が転送を開始しようとしているこの男です。それはアカウントの所有者ではありません、それは確かです。

サーバーはこれをどのように認識しますか?要求者を認証するsession_idクッキーがないからです。

ユーザー名とパスワードでサインインすると、サーバーはブラウザにsession_idクッキーを設定します。そのように、あなたはあなたのユーザ名とパスワードでそれぞれのリクエストを認証する必要はありません。ブラウザがsession_id Cookieを送信すると、サーバーは次のことを認識します。

おお、それはジョン・ドウです。 2.5分前に彼はサインインに成功しました。彼は行ってもいいです。

ハッカーは考えるかもしれません:

うーん。通常のHTTPリクエストは機能しませんが、そのsession_idクッキーを手に入れることができれば、私は金持ちになるでしょう。

ユーザーのブラウザにはbank.comドメイン用に設定されたたくさんのクッキーがあります。ユーザーがbank.comドメインにリクエストを送信するたびに、すべてのCookieが一緒に送信されます。 session_idクッキーを含みます。

したがって、ハッカーが自分のアカウントにお金を振り込むGETリクエストを作成するために you を取得することができれば、彼は成功するでしょう。どうして彼はあなたをだまそうとしたのでしょうか。クロスサイトリクエストフォージェリ.

実はかなり単純です。ハッカーはあなたに彼のウェブサイトを訪問させるだけかもしれません。彼のウェブサイトで、彼は次の画像タグを持つことができました:

<img src="http://bank.com/transfer?amount=$1000000&account-to=999999">

ユーザーのブラウザがその画像タグに遭遇すると、そのURLにGETリクエストを送信します。そして要求は彼のブラウザから来るので、それはbank.comに関連したすべてのクッキーを一緒に送ります。ユーザーが最近bank.com...にサインインした場合、session_id Cookieが設定され、サーバーはユーザーが999999のアカウントに1,000,000ドルを転送しようとしていると判断します。

enter image description here

危険なサイトには絶対にアクセスしないでください。

それだけでは不十分です。誰かがその画像をFacebookに投稿し、それがあなたの壁に表示されたらどうなりますか?あなたが訪問しているサイトにXSS攻撃で注入された場合はどうなりますか?

そんなに悪くない。 GETリクエストのみがこの脆弱性の影響を受けます。

違います。 POSTリクエストを送信するフォームは動的に生成することができます。これは セキュリティに関するRailsガイド :の例です。

<a href="http://www.harmless.com/" onclick="
  var f = document.createElement('form');
  f.style.display = 'none';
  this.parentNode.appendChild(f);
  f.method = 'POST';
  f.action = 'http://www.example.com/account/destroy';
  f.submit();
  return false;">To the harmless survey</a>

信頼性トークン

あなたのApplicationControllerがこれを持っていると:

protect_from_forgery with: :exception

この:

<%= form_tag do %>
  Form contents
<% end %>

これにコンパイルされます:

<form accept-charset="UTF-8" action="/" method="post">
  <input name="utf8" type="hidden" value="&#x2713;" />
  <input name="authenticity_token" type="hidden" value="J7CBxfHalt49OSHp27hblqK20c9PgwJ108nDHX/8Cts=" />
  Form contents
</form>

特に、次のものが生成されます。

<input name="authenticity_token" type="hidden" value="J7CBxfHalt49OSHp27hblqK20c9PgwJ108nDHX/8Cts=" />

CSRF攻撃から保護するために、Railsが認証トークンがリクエストと一緒に送信されているのを確認できない場合、そのリクエストは安全とは見なされません。

攻撃者はこのトークンが何であるかをどのように知っているはずですか?フォームが生成されるたびに異なる値がランダムに生成されます。

enter image description here

クロスサイトスクリプティング(XSS)攻撃 - それはその方法です。しかし、それは別の日の異なる脆弱性です。

35
Adam Zerner

Authenticity Tokenはとても重要なので、Rails 3.0以降ではあなたが使えるのです。

 <%= token_tag nil %>

作成する

<input name="authenticity_token" type="hidden" value="token_value">

どこでも

32
Yuan He

同じクライアントから複数の同時要求がある場合は、Authenticity Tokenメカニズムが競合状態になる可能性があります。この状況では、あなたのサーバは一つだけであるべきときに複数の真正性トークンを生成することができ、そしてセッションクッキートークンが上書きされているので、フォームで以前のトークンを受け取ったクライアントは次のリクエストで失敗します。この問題についての記事と完全に簡単な解決策はここにありません: http://www.paulbutcher.com/2007/05/race-conditions-in-Rails-sessions-and-how-to-fix-それら/

25
jdp

メソッドauthenticity_tokenが必要なところ

post、put、deleteのようなべき等法の場合はauthenticity_tokenが必要です。これはべき等法がデータに影響を与えるためです。

なぜそれが必要なのか

悪の行為を防ぐことが必要です。 authenticicity_tokenは、リソースを作成または更新するためにWebページ上にフォームが作成されるたびにセッションに格納され、その後、認証性トークンはhiddenフィールドに格納され、サーバー上のフォームとともに送信されます。アクションを実行する前にユーザーが送信したauthenticicity_tokenはセッションに保存されたauthenticity_tokenとクロスチェックされます。 authenticity_tokenが同じであれば処理は続行され、そうでなければアクションは実行されません。

8
uma

authentication_tokenとは何ですか?

これは、他のアプリやサイトからではなく、アプリページからユーザーがアクションを要求または実行していることを確認するためにRailsアプリケーションが使用するランダムな文字列です。

authentication_tokenが必要なのはなぜですか?

アプリやサイトをクロスサイトリクエストフォージェリから保護するため。

フォームにauthentication_tokenを追加するにはどうすればいいですか?

Form_forタグを使用してフォームを生成している場合はauthentication_tokenが自動的に追加されます。それ以外の場合は<%= csrf_meta_tag %>を使用できます。

3
Pradeep Sapkota