私はこれまで何度も経験してきたように、RailsのAuthenticity Tokenに関するいくつかの問題に遭遇しています。
しかし、私は本当にこの問題を解決し続けたいだけではありません。本当にAuthenticityトークンを理解したいのですが。さて、私の質問は、このテーマに関する完全な情報源を持っているか、それともここで詳細に説明するのにあなたの時間を費やすだろうか?
何が起こるか
ユーザーがフォームを表示してリソースを作成、更新、または破棄すると、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によるコメント を確認してください。彼は私がここでやったよりも良い方法でそれを説明しています。
認証トークンは、フォームがWebサイトから送信されていることをユーザーが認識できるように設計されています。それはあなたのマシンだけが知ることができるユニークな識別子でそれが走るマシンから生成され、クロスサイトリクエストフォージェリ攻撃を防ぐのに役立ちます。
RailsがAJAXスクリプトへのアクセスを拒否するのが困難な場合は、次のようにします。
<%= form_authenticity_token %>
フォームを作成するときに正しいトークンを生成します。
ドキュメント でそれについてもっと読むことができます。
認証トークンは、クロスサイトリクエストフォージェリ(CSRF)に対する対策です。 CSRFとは何ですか?
攻撃者がセッショントークンを知らなくても、潜在的にセッションをハイジャックすることができる方法です。
シナリオ :
CSRFソリューション :
防止されるであろう最小限の攻撃の例
私のウェブサイトで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トークンが効力を発揮したことです。
そのため、本物のブラウザのフォームは次のようになります。
<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は、キャッシュされた古いフラグメントのフォームのトークンを更新しようとします。
その他の予防方法
X-Requested-With
:Origin
ヘッダーの値を確認します。 https://security.stackexchange.com/questions/91165/why-is-the-synchronizer-token-pattern-preferred-over-the-Origin-header-check-toAuthenticity Token
はRailsの 防止'クロスサイトリクエストフォージェリ(CSRFまたはXSRF)攻撃' です。
簡単に言うと、WebアプリケーションへのPUT/POST/DELETE(コンテンツを変更できるメソッド)リクエストは、第三者(攻撃者)からではなくクライアントのブラウザから行われるようになっています。クライアント側で作成されたクッキーにアクセスできます。
信頼性トークンは、クロスサイトリクエストフォージェリ攻撃(CSRF)を防ぐために使用されます。信頼性トークンを理解するには、まずCSRF攻撃を理解する必要があります。
あなたがbank.com
の作者であるとします。あなたのサイトには、GETリクエストで他の口座に送金するためのフォームがあります。
ハッカーがHTTPリクエストをサーバーに送信してGET /transfer?amount=$1000000&account-to=999999
と言っている可能性があります。
違う。ハッカーの攻撃はうまくいきません。サーバーは基本的に考えるでしょうか?
え?誰が転送を開始しようとしているこの男です。それはアカウントの所有者ではありません、それは確かです。
サーバーはこれをどのように認識しますか?要求者を認証する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ドルを転送しようとしていると判断します。
危険なサイトには絶対にアクセスしないでください。
それだけでは不十分です。誰かがその画像を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="✓" />
<input name="authenticity_token" type="hidden" value="J7CBxfHalt49OSHp27hblqK20c9PgwJ108nDHX/8Cts=" />
Form contents
</form>
特に、次のものが生成されます。
<input name="authenticity_token" type="hidden" value="J7CBxfHalt49OSHp27hblqK20c9PgwJ108nDHX/8Cts=" />
CSRF攻撃から保護するために、Railsが認証トークンがリクエストと一緒に送信されているのを確認できない場合、そのリクエストは安全とは見なされません。
攻撃者はこのトークンが何であるかをどのように知っているはずですか?フォームが生成されるたびに異なる値がランダムに生成されます。
クロスサイトスクリプティング(XSS)攻撃 - それはその方法です。しかし、それは別の日の異なる脆弱性です。
Authenticity Token
はとても重要なので、Rails 3.0以降ではあなたが使えるのです。
<%= token_tag nil %>
作成する
<input name="authenticity_token" type="hidden" value="token_value">
どこでも
同じクライアントから複数の同時要求がある場合は、Authenticity Tokenメカニズムが競合状態になる可能性があります。この状況では、あなたのサーバは一つだけであるべきときに複数の真正性トークンを生成することができ、そしてセッションクッキートークンが上書きされているので、フォームで以前のトークンを受け取ったクライアントは次のリクエストで失敗します。この問題についての記事と完全に簡単な解決策はここにありません: http://www.paulbutcher.com/2007/05/race-conditions-in-Rails-sessions-and-how-to-fix-それら/
メソッドauthenticity_token
が必要なところ
post、put、deleteのようなべき等法の場合は
authenticity_token
が必要です。これはべき等法がデータに影響を与えるためです。
なぜそれが必要なのか
悪の行為を防ぐことが必要です。 authenticicity_tokenは、リソースを作成または更新するためにWebページ上にフォームが作成されるたびにセッションに格納され、その後、認証性トークンはhiddenフィールドに格納され、サーバー上のフォームとともに送信されます。アクションを実行する前にユーザーが送信したauthenticicity_tokenはセッションに保存された
authenticity_token
とクロスチェックされます。authenticity_token
が同じであれば処理は続行され、そうでなければアクションは実行されません。
authentication_tokenとは何ですか?
これは、他のアプリやサイトからではなく、アプリページからユーザーがアクションを要求または実行していることを確認するためにRailsアプリケーションが使用するランダムな文字列です。
authentication_tokenが必要なのはなぜですか?
アプリやサイトをクロスサイトリクエストフォージェリから保護するため。
フォームにauthentication_tokenを追加するにはどうすればいいですか?
Form_forタグを使用してフォームを生成している場合はauthentication_tokenが自動的に追加されます。それ以外の場合は<%= csrf_meta_tag %>
を使用できます。