रेल - "चेतावनी: सीएसआरएफ टोकन प्रामाणिकता को सत्यापित नहीं कर सकते हैं" जइस डेविस अनुरोधों के लिए


82

मैं एक JSON अनुरोध के साथ पास करने के लिए CSRF टोकन कैसे प्राप्त कर सकता हूं?

मुझे पता है कि सुरक्षा कारणों से सभी अनुरोध प्रकार (JSON / XML सहित) पर CSRF टोकन की जाँच कर रहा है

मैं अपने कंट्रोलर में रख सकता हूं skip_before_filter :verify_authenticity_token, लेकिन मैं CRSF प्रोटेक्शन खो दूंगा (उचित नहीं :-))।

यह इसी तरह (अभी भी स्वीकार नहीं किया गया) उत्तर बताता है

के साथ टोकन प्राप्त करें <%= form_authenticity_token %>

सवाल यह है कि कैसे? क्या मुझे टोकन पुनः प्राप्त करने के लिए अपने किसी भी पेज पर पहली कॉल करने की आवश्यकता है और फिर डेविस के साथ अपना वास्तविक प्रमाणीकरण करना है? या यह एक सूचना है जिसे मैं अपने सर्वर से प्राप्त कर सकता हूं और फिर लगातार उपयोग कर सकता हूं (जब तक कि मैं इसे स्वयं सर्वर पर नहीं बदलूं)?

जवाबों:


127

संपादित करें :

रेल 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 के लिए निम्नलिखित सेटिंग करना जहां "पैरामीटर" आपके पैरामीटर हैं:


[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' के रूप में चिह्नित कर रहा है। और यही कारण है कि परिभाषा द्वारा रेल एक चेतावनी जारी कर रही है। मैं चाहता हूं कि मेरा जसन ठीक से टोकन पास करने में सक्षम हो, अन्यथा लॉग में चेतावनी देना ठीक है।

21
आपको हमलों से अवगत कराया जाता है, यही कारण है कि वे अनुशंसा करते हैं कि आपके पास फ़िल्टर बंद करने के दौरान कुछ अन्य सुरक्षा है। आमतौर पर एपीआई अनुरोधों के लिए अनुरोधकर्ता पोस्ट डेटा के साथ एक एपीआई कुंजी भेजेगा, जिसे आप वांछित विधि को निष्पादित करने से पहले सत्यापित करेंगे।
रयान क्रू

18
रेल 4 में आप कुछ इस तरह कर सकते हैं:protect_from_forgery with: :null_session, :if => Proc.new { |c| c.request.format == 'application/json' }
genkilabs 21

2
@genkilabs मुझे वह पसंद है, जिसने 4 उपयोगकर्ताओं को जवाब देने के लिए जोड़ा, धन्यवाद =]
रेयान क्रू ने

1
दो काम जो मैंने अभी अपने रेल और iOS ऐप में इस काम को करने के लिए किया था: 1) मुझे कोई कारण नहीं दिखाई दिया कि हम रूबी में पुराने और नए-नए स्टाइल के हैश सिंटैक्स को क्यों मिला रहे हैं, इसलिए मेरे कंट्रोलर में कोड इस तरह दिखता है: protect_from_forgery with: :null_session, if: Proc.new { |c| c.request.format == 'application/json' }2) इस सवाल से संबंधित नहीं है, लेकिन iOS से पोस्टिंग JSON के विषय से संबंधित है, क्योंकि मैं उपयोग कर रहा हूं AFNetworkingऔर रेल स्वचालित रूप से मापदंडों को लपेट नहीं रहा था, मैंने निम्नलिखित कार्य किया:manager.requestSerializer = [AFJSONRequestSerializer serializer];
14'14

18

आप एक कस्टम हेडर का उपयोग करके, एक सफल लॉग-इन के बाद CSRF टोकन भेज सकते हैं।

उदाहरण के लिए, इसे अपने सत्रों में बनाएँ:

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

यह टोकन तब तक मान्य है जब तक कि आप लॉग-इन या (लॉग-आउट यदि आप अपने एपीआई के माध्यम से इसका समर्थन करते हैं)। आपका क्लाइंट लॉग-इन प्रतिक्रिया हेडर से टोकन निकाल और स्टोर कर सकता है। फिर, प्रत्येक POST / PUT / DELETE अनुरोध को लॉग-इन समय पर प्राप्त मूल्य के साथ X-CSRF-टोकन हेडर सेट करना होगा।

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 %>"/>

या यदि आप एक jjery अजाक्स पोस्ट चाहते हैं:

$.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);
    }
});

मूल रूप से जब आप अपना जसन डेटा पोस्ट करते हैं तो डेटा में केवल एक मान्य प्रमाणिकता_टोकन फ़ील्ड जोड़ें postऔर चेतावनी दूर हो जानी चाहिए ...


IMHO यह केवल लकड़हारे में चेतावनी नहीं देनी चाहिए, लेकिन डिफ़ॉल्ट रूप से वैध सीएसआरएफ टैग के बिना पूरी तरह से पद छोड़ दें, यह सिर्फ चेतावनी पोस्ट करता है और डेटा को ठीक करता है ...
वाल्टर स्क्रेपर

छिपे हुए प्रामाणिकता टोकन इनपुट फ़ील्ड को करने का छोटा तरीका है = token_tag(nil)(शून्य महत्वपूर्ण है)
यो लुडके

रेल के पुराने संस्करणों में, टैग बहुवचन समाप्त होता है। <% = csrf_meta_tags%>
साइबरन

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


मुझे यकीन नहीं है कि आप ऐसा करना चाहते हैं - ब्राउज़र JSON API का उपयोग कर सकते हैं।
जो वान डाइक

धन्यवाद! इस समस्या को हल करने के लिए एक त्वरित (और गंदे) तरीके की आवश्यकता है और जो मैं हासिल करने की कोशिश कर रहा हूं उसके लिए यह पर्याप्त रूप से काम कर सकता है।
NerdyTherapist

लिंक्ड डॉक (अब रेल 5 के लिए अपडेट किया गया) प्रतीत होता है: protect_from_forgery with: :exception, unless: -> { request.format.json? }और इसने मेरे लिए काम किया। धन्यवाद।
अकोस्टैडिनोव

1
यह सिर्फ चेक को निष्क्रिय करता है, जो समस्या से बचा जाता है। अगर और ऐप इसे अक्षम करने जा रहा है तो जालसाजी से सुरक्षा प्राप्त करने की बात क्या है?
jefflunt

3

चिंता की बात यह है कि रेल 3.2.3 में हमें अब उत्पादन में सीएसआरएफ की चेतावनी मिलती है। लेकिन पोस्ट विफल नहीं होती है! मैं चाहता हूं कि यह विफल हो जाए क्योंकि यह मुझे हमलों से बचाता है। और आप फ़िल्टर btw से पहले jquery के साथ csrf टोकन जोड़ सकते हैं:

http://jasoncodes.com/posts/rails-csrf-vulnerability


2

मैंने नीचे इस्तेमाल किया है। का उपयोग कर शामिल हैं? इसलिए यदि सामग्री का प्रकार अनुप्रयोग / 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

मेरे पास रेल के निम्नलिखित संस्करण के साथ एक ही मुद्दा था:
मणि 'रेल',: git => 'git: //github.com/rails/rails.git': शाखा => '3-2-स्थिर'

मैंने 3.2.2 में अपडेट किया और मेरे लिए अब सब कुछ ठीक है। :)
मणि 'रेल', '3.2.2'


सलाह के लिये धन्यवाद। मैंने इसे आज़माया, लेकिन मुझे अभी भी एक ही चेतावनी हैWARNING: Can't verify CSRF token authenticity

0

मैं आज रात उसी मुद्दे पर भाग गया। ऐसा होने का कारण यह है कि जब आप अंतिम सीएसआरएफ-टोकन में हस्ताक्षर करते हैं, तो अब मान्य नहीं है। मैंने जो किया था: $("meta[name=csrf-token]").attr('content', '<%= form_authenticity_token %>');आपके ऐप / विचार / वसीयत / सत्र / create.js.rb में।

अब इसके पास एक वैध सीएसआरएफ-टोकन है :) मुझे आशा है कि यह मदद करता है


0

विकास / परीक्षण मोड के लिए भी।

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

यह चेतावनी दिखाती है कि आप उपयोग कर रहे हैं :null_session, क्योंकि रेल 4.1 में यह डिफ़ॉल्ट रूप से काम करता है यदि कोई with:विकल्प निर्दिष्ट नहीं किया गया है।

protect_from_forgery
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.