rails-「警告:CSRFトークンの信頼性を検証できません」jsonデバイスリクエスト


82

JSONリクエストで渡すCSRFトークンを取得するにはどうすればよいですか?

セキュリティ上の理由から、Railsはすべてのリクエストタイプ(JSON / XMLを含む)でCSRFトークンチェックしていることを知っています。

コントローラをskip_before_filter :verify_authenticity_token挿入することはできますが、CRSF保護が失われます(お勧めできません:-))。

この同様の(まだ受け入れられていない)回答は、

でトークンを取得します <%= form_authenticity_token %>

問題はどのようにですか?トークンを取得するためにページのいずれかを最初に呼び出してから、Deviseで実際の認証を行う必要がありますか?または、サーバーから取得して一貫して使用できる1回限りの情報ですか(サーバー自体で手動で変更するまで)?

回答:


127

編集

Rails 4では、@ genkilabsが以下のコメントで提案しているものを使用しています。

protect_from_forgery with: :null_session, if: Proc.new { |c| c.request.format == 'application/json' }

これは、組み込みのセキュリティを完全にオフにする代わりに、CSRFトークンなしでサーバーに何かがヒットしたときに存在する可能性のあるすべてのセッションを強制終了します。


skip_before_filter :verify_authenticity_token, :if => Proc.new { |c| c.request.format == 'application/json' }

これにより、適切にマークされたjson投稿/プットのCSRFチェックがオフになります。

たとえば、iOSでは、NSURLRequestに以下を設定します。ここで「parameters」はパラメーターです。


[request setHTTPMethod:@"POST"];

[request setValue:@"application/json" 
       forHTTPHeaderField:@"content-type"];

[request setValue:@"application/json" 
       forHTTPHeaderField:@"accept"];

[request setHTTPBody:[NSData dataWithBytes:[parameters UTF8String] 
                                            length:[parameters length]]];

3
これを行うと、攻撃者がフォーマットを「json」としてマークしている場合、攻撃にさらされます。そしてそれが、定義によるRailsが警告を発している理由です。jsonにトークンを適切に渡せるようにしたいのですが、そうでない場合はログに警告が表示されても問題ありません。

21
攻撃にさらされるため、フィルターをオフにするときに他のセキュリティを設定することをお勧めします。通常、APIリクエストの場合、リクエスターは投稿データとともにAPIキーを送信し、目的のメソッドを実行する前に確認します。
ライアンクルー2012

18
:レール4では、あなたのような何かを行うことができますprotect_from_forgery with: :null_session, :if => Proc.new { |c| c.request.format == 'application/json' }
genkilabs

2
@genkilabs私はそれが好きで、rails 4ユーザーの回答に追加しました、ありがとう=]
Ryan Crews

1
Rails&iOSアプリでこれを機能させるために今行った2つのこと:1)Rubyで古いスタイルと新しいスタイルのハッシュ構文を混合している理由がわからなかったため、コントローラーのコードは次のようになります。protect_from_forgery with: :null_session, if: Proc.new { |c| c.request.format == 'application/json' }この質問に関係のないが、私が使用していることから、iOS版からJSONを掲示するの主題に関連する2) AFNetworking:とRails自動的にパラメータを包むいなかった、私は次のようでしたmanager.requestSerializer = [AFJSONRequestSerializer serializer];
mharper

18

ログインに成功した後、カスタムヘッダーを使用してCSRFトークンを送信できます。

たとえば、これをセッションに入れます#create:

response.headers['X-CSRF-Token'] = form_authenticity_token

CSRFトークンを提供するサンプルのログイン応答ヘッダー:

HTTP/1.1 200 OK
Cache-Control: max-age=0, private, must-revalidate
Connection: Keep-Alive
Content-Length: 35
Content-Type: application/json; charset=utf-8
Date: Mon, 22 Oct 2012 11:39:04 GMT
Etag: "9d719d3b9aabd413c3603e04e8a3933d"
Server: WEBrick/1.3.1 (Ruby/1.9.3/2012-10-12)
Set-Cookie: [cut for readability] 
X-Csrf-Token: PbtMPfrszxH6QfRcWJCCyRo7BlxJUPU7HqC2uz2tKGw=
X-Request-Id: 178746992d7aca928c876818fcdd4c96
X-Runtime: 0.169792
X-Ua-Compatible: IE=Edge

このトークンは、再度ログインするか(APIを介してこれをサポートしている場合はログアウトする)まで有効です。クライアントは、ログイン応答ヘッダーからトークンを抽出して保存できます。次に、各POST / PUT / DELETEリクエストは、ログイン時に受信した値でX-CSRF-Tokenヘッダーを設定する必要があります。

CSRFトークンを使用したPOSTヘッダーのサンプル:

POST /api/report HTTP/1.1
Accept: application/json
Accept-Encoding: gzip, deflate, compress
Content-Type: application/json; charset=utf-8
Cookie: [cut for readability]
Host: localhost:3000
User-Agent: HTTPie/0.3.0
X-CSRF-Token: PbtMPfrszxH6QfRcWJCCyRo7BlxJUPU7HqC2uz2tKGw=

ドキュメント:form_authenticity_token


18

確かに最も簡単な方法。ヘッダーの変更を気にしないでください。

あなたが持っていることを確認してください:

<%= csrf_meta_tag %>

あなたの中で layouts/application.html.erb

次のように非表示の入力フィールドを実行するだけです。

<input name="authenticity_token" 
       type="hidden" 
       value="<%= form_authenticity_token %>"/>

または、jquery ajax postが必要な場合:

$.ajax({     
    type: 'POST',
    url: "<%= someregistration_path %>",
    data: { "firstname": "text_data_1", "last_name": "text_data2", "authenticity_token": "<%= form_authenticity_token %>" },                                                                                  
    error: function( xhr ){ 
      alert("ERROR ON SUBMIT");
    },
    success: function( data ){ 
      //data response can contain what we want here...
      console.log("SUCCESS, data="+data);
    }
});

基本的に、jsonデータを投稿するときは、有効なauthenticity_tokenフィールドをデータに追加するだけpostで、警告が消えるはずです...


私見では、ロガーに警告を表示するだけでなく、有効なcsrfタグのない投稿を完全に破棄する必要があります。デフォルトでは、警告を投稿してデータを正常に送信します...
Walter Schreppers 2013年

非表示の信頼性トークン入力フィールドを実行する短い方法= token_tag(nil)
次のとおり

古いバージョンのレールでは、タグは複数形で終わります。<%= csrf_meta_tags%>
cyonder 2017年

4

私はそのエラーを次のように解決しました:

class ApplicationController < ActionController::Base
  protect_from_forgery
  skip_before_action :verify_authenticity_token, if: :json_request?

  protected

  def json_request?
    request.format.json?
  end
end

ソース:http//api.rubyonrails.org/classes/ActionController/RequestForgeryProtection.html


これを実行するかどうかはわかりません。ブラウザーはJSONAPIを使用できます。
Joe Van Dyk 2016年

ありがとうございました!この問題を解決するための迅速な(そして汚い)方法が必要でした。これは私が達成しようとしていることには十分にうまくいくかもしれません。
NerdyTherapist 2016年

リンクされたドキュメント(現在Rails 5用に更新されています)は次のように見えます:protect_from_forgery with: :exception, unless: -> { request.format.json? }そしてそれは私のために働きました。ありがとう。
akostadinov 2016

1
これにより、チェックが無効になり、問題が回避されます。アプリがこれを無効にする場合、偽造からの保護をオンにすることのポイントは何ですか?
jefflunt 2016年


2

以下を使用しました。インクルードを使用しますか?したがって、コンテンツタイプがapplication / json; charset = utf-8の場合、それはまだ機能しています。

protect_from_forgery with: :null_session, if: Proc.new { |c| c.request.format.include? 'application/json' }

2

この答えはより良いです。

XMLHttpRequestを送信する前に、余分な労力(トークンが追加される)なしでCSRF-TOKEN検証を維持できます。JQueryはなく、コピー/貼り付けと更新だけでもありません。

このコードを追加するだけです。

(function() {
    var send = XMLHttpRequest.prototype.send,
        token = $('meta[name=csrf-token]').attr('content');
    XMLHttpRequest.prototype.send = function(data) {
        this.setRequestHeader('X-CSRF-Token', token);
        return send.apply(this, arguments);
    };
}());

1

次のバージョンのRailsでも同じ問題が発生しました
:gem'rails '、:git =>' git://github.com/rails/rails.git '、:branch =>' 3-2-stable '

3.2.2にアップデートしましたが、すべて正常に動作しています。:)
gem'rails '、' 3.2.2 '


提案をありがとう。試してみましたが、同じ警告が表示されますWARNING: Can't verify CSRF token authenticity

0

私は今夜​​同じ問題に遭遇しました。発生する理由は、最後のcsrfトークンにサインインすると無効になるためです。私がしたことは: $("meta[name=csrf-token]").attr('content', '<%= form_authenticity_token %>');あなたのapp / views / devise / sessions /create.js.rbで。

今では有効なcsrfトークンがあります:)お役に立てば幸いです


0

開発/テストモードにも使用できます。

protect_from_forgery with: :exception unless %w(development test).include? Rails.env

この警告は、を使用しているために表示されます:null_session。Rails4.1では、with:オプションが指定されていない場合、デフォルトで機能します。

protect_from_forgery
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.