Ruby on Rails 5.2 - ActionController::RequestForgeryProtection

मॉड्यूल एक्शनकंट्रोलर :: RequestForgeryProtection




ruby

मॉड्यूल एक्शनकंट्रोलर :: RequestForgeryProtection

शामिल मॉड्यूल:
AbstractController :: सहायकों , AbstractController::Callbacks

नियंत्रक कार्रवाइयाँ आपके आवेदन के लिए प्रदान किए गए HTML में एक टोकन शामिल करके क्रॉस-साइट रिक्वेस्ट फॉरगेरी (CSRF) हमलों से सुरक्षित हैं। यह टोकन सत्र में एक यादृच्छिक स्ट्रिंग के रूप में संग्रहीत किया जाता है, जिसमें एक हमलावर की पहुंच नहीं होती है। जब कोई अनुरोध आपके आवेदन पर पहुंचता है, तो रेल सत्र में टोकन के साथ प्राप्त टोकन की पुष्टि करता है। GET के अनुरोधों को छोड़कर सभी अनुरोधों की जाँच की जाती है क्योंकि ये निष्प्रभावी होने चाहिए। ध्यान रखें कि सभी सत्र-उन्मुख अनुरोध CSRF संरक्षित होने चाहिए, जिसमें जावास्क्रिप्ट और HTML अनुरोध शामिल हैं।

चूंकि HTML और जावास्क्रिप्ट अनुरोध आमतौर पर ब्राउज़र से किए जाते हैं, इसलिए हमें वेब ब्राउज़र के लिए अनुरोध प्रामाणिकता को सत्यापित करना सुनिश्चित करना होगा। हम अपने नियंत्रकों में protect_from_forgery विधि का उपयोग करके इस प्रकार के अनुरोधों के लिए सत्र-उन्मुख प्रमाणीकरण का उपयोग कर सकते हैं।

GET अनुरोध संरक्षित नहीं हैं क्योंकि उनके डेटाबेस पर लिखने जैसे दुष्प्रभाव नहीं हैं और संवेदनशील जानकारी लीक नहीं हुई है। जावास्क्रिप्ट अनुरोध एक अपवाद हैं: आपकी साइट पर जावास्क्रिप्ट URL का संदर्भ देने के लिए एक तृतीय-पक्ष साइट <script> टैग का उपयोग कर सकती है। जब आपकी जावास्क्रिप्ट प्रतिक्रिया उनकी साइट पर लोड होती है, तो यह निष्पादित होता है। उनके अंत में ध्यान से तैयार किए गए जावास्क्रिप्ट के साथ, आपकी जावास्क्रिप्ट प्रतिक्रिया में संवेदनशील डेटा निकाला जा सकता है। इसे रोकने के लिए, केवल XmlHttpRequest (XHR या Ajax के रूप में जाना जाता है) अनुरोधों को जावास्क्रिप्ट प्रतिक्रियाओं के लिए GET अनुरोध करने की अनुमति है।

यह याद रखना महत्वपूर्ण है कि XML या JSON अनुरोध भी प्रभावित होते हैं और यदि आप एक API निर्माण कर रहे हैं तो आपको ApplicationController में डिफ़ॉल्ट सुरक्षा विधि बदलनी चाहिए (डिफ़ॉल्ट रूप से :exception ):

class ApplicationController < ActionController::Base
  protect_from_forgery unless: -> { request.format.json? }
end

CSRF सुरक्षा को protect_from_forgery विधि से चालू किया गया है। डिफ़ॉल्ट रूप से protect_from_forgery आपके सत्र की सुरक्षा करता है :null_session विधि, जो अनुरोध के दौरान एक खाली सत्र प्रदान करती है।

हम एपीआई के लिए CSRF सुरक्षा को निष्क्रिय करना चाहते हैं क्योंकि वे आमतौर पर राज्य-कम करने के लिए डिज़ाइन किए जाते हैं। यही है, अनुरोध API क्लाइंट रेल के बजाय आपके लिए सत्र को संभाल लेगा।

टोकन पैरामीटर को डिफ़ॉल्ट रूप से authenticity_token नाम दिया गया है। इस टोकन का नाम और मान HTML लेआउट में csrf_meta_tags को शामिल करके रेंडर करने वाले हर लेआउट में जोड़ा जाना चाहिए।

रूबी सिक्योरिटी गाइड पर रूबी में सीएसआरएफ हमलों और अपने आवेदन को सुरक्षित करने के बारे में अधिक जानें।

स्थिरांक

AUTHENTICITY_TOKEN_LENGTH
NULL_ORIGIN_MESSAGE

निजी उदाहरण तरीके

any_authenticity_token_valid? () स्रोत दिखाएं
# File actionpack/lib/action_controller/metal/request_forgery_protection.rb, line 295
def any_authenticity_token_valid? # :doc:
  request_authenticity_tokens.any? do |token|
    valid_authenticity_token?(session, token)
  end
end

जाँचता है कि अनुरोध से कोई प्रामाणिकता मान्य है या नहीं।

तुलना_विस्तृत_लोकनायक (टोकन, सत्र) स्रोत दिखाएँ
# File actionpack/lib/action_controller/metal/request_forgery_protection.rb, line 372
def compare_with_real_token(token, session) # :doc:
  ActiveSupport::SecurityUtils.fixed_length_secure_compare(token, real_csrf_token(session))
end
form_authenticity_param () स्रोत दिखाएं
# File actionpack/lib/action_controller/metal/request_forgery_protection.rb, line 410
def form_authenticity_param # :doc:
  params[request_forgery_protection_token]
end

प्रपत्र की प्रामाणिकता पैरामीटर। अपने स्वयं के प्रदान करने के लिए ओवरराइड करें।

handle_unverified_request () स्रोत दिखाएं
# File actionpack/lib/action_controller/metal/request_forgery_protection.rb, line 242
def handle_unverified_request # :doc:
  forgery_protection_strategy.new(self).handle_unverified_request
end
mark_for_same_origin_verification! () स्रोत दिखाएं
# File actionpack/lib/action_controller/metal/request_forgery_protection.rb, line 267
def mark_for_same_origin_verification! # :doc:
  @marked_for_same_origin_verification = request.get?
end

GET अनुरोधों को प्रतिपादन के बाद क्रॉस-मूल जावास्क्रिप्ट के लिए जाँच की जाती है।

marked_for_same_origin_verification? () स्रोत दिखाएं
# File actionpack/lib/action_controller/metal/request_forgery_protection.rb, line 273
def marked_for_same_origin_verification? # :doc:
  @marked_for_same_origin_verification ||= false
end

यदि पहले से verify_authenticity_token किया गया है, तो सत्यापित करें कि जावास्क्रिप्ट प्रतिक्रियाएं केवल उसी-मूल GET अनुरोधों के लिए दी जाती हैं।

masked_authenticity_token (सत्र, form_options: {}) स्रोत दिखाएं
# File actionpack/lib/action_controller/metal/request_forgery_protection.rb, line 314
def masked_authenticity_token(session, form_options: {}) # :doc:
  action, method = form_options.values_at(:action, :method)

  raw_token = if per_form_csrf_tokens && action && method
    action_path = normalize_action_path(action)
    per_form_csrf_token(session, action_path, method)
  else
    real_csrf_token(session)
  end

  one_time_pad = SecureRandom.random_bytes(AUTHENTICITY_TOKEN_LENGTH)
  encrypted_csrf_token = xor_byte_strings(one_time_pad, raw_token)
  masked_token = one_time_pad + encrypted_csrf_token
  Base64.strict_encode64(masked_token)
end

प्रत्येक अनुरोध पर बदलती प्रामाणिकता टोकन का एक नकाबपोश संस्करण बनाता है। ब्रेकिंग जैसे SSL हमलों को कम करने के लिए मास्किंग का उपयोग किया जाता है।

non_xhr_javascript_response? () स्रोत दिखाएं
# File actionpack/lib/action_controller/metal/request_forgery_protection.rb, line 278
def non_xhr_javascript_response? # :doc:
  content_type =~ %r(\Atext/javascript) && !request.xhr?
end

क्रॉस-मूल जावास्क्रिप्ट प्रतिक्रियाओं के लिए जाँच करें।

normalize_action_path (क्रिया_पथ) स्रोत दिखाएँ
# File actionpack/lib/action_controller/metal/request_forgery_protection.rb, line 440
def normalize_action_path(action_path) # :doc:
  uri = URI.parse(action_path)
  uri.path.chomp("/")
end
per_form_csrf_token (सत्र, क्रिया_पथ, विधि) स्रोत दिखाएं
# File actionpack/lib/action_controller/metal/request_forgery_protection.rb, line 395
def per_form_csrf_token(session, action_path, method) # :doc:
  OpenSSL::HMAC.digest(
    OpenSSL::Digest::SHA256.new,
    real_csrf_token(session),
    [action_path, method.downcase].join("#")
  )
end
protect_against_forgery? () स्रोत दिखाएं
# File actionpack/lib/action_controller/metal/request_forgery_protection.rb, line 415
def protect_against_forgery? # :doc:
  allow_forgery_protection
end

जाँचता है कि क्या नियंत्रक जालसाज़ी सुरक्षा की अनुमति देता है।

real_csrf_token (सत्र) स्रोत दिखाएँ
# File actionpack/lib/action_controller/metal/request_forgery_protection.rb, line 390
def real_csrf_token(session) # :doc:
  session[:_csrf_token] ||= SecureRandom.base64(AUTHENTICITY_TOKEN_LENGTH)
  Base64.strict_decode64(session[:_csrf_token])
end
request_authenticity_tokens () स्रोत दिखाएं
# File actionpack/lib/action_controller/metal/request_forgery_protection.rb, line 302
def request_authenticity_tokens # :doc:
  [form_authenticity_param, request.x_csrf_token]
end

अनुरोध में भेजी गई संभावित प्रामाणिकता टोकन।

unmask_token (masked_token) स्रोत दिखाएँ
# File actionpack/lib/action_controller/metal/request_forgery_protection.rb, line 364
def unmask_token(masked_token) # :doc:
  # Split the token into the one-time pad and the encrypted
  # value and decrypt it.
  one_time_pad = masked_token[0...AUTHENTICITY_TOKEN_LENGTH]
  encrypted_csrf_token = masked_token[AUTHENTICITY_TOKEN_LENGTH..-1]
  xor_byte_strings(one_time_pad, encrypted_csrf_token)
end
valid_authenticity_token? (सत्र, एन्कोडेड_मास्कड_टोकन) स्रोत दिखाएं
# File actionpack/lib/action_controller/metal/request_forgery_protection.rb, line 333
def valid_authenticity_token?(session, encoded_masked_token) # :doc:
  if encoded_masked_token.nil? || encoded_masked_token.empty? || !encoded_masked_token.is_a?(String)
    return false
  end

  begin
    masked_token = Base64.strict_decode64(encoded_masked_token)
  rescue ArgumentError # encoded_masked_token is invalid Base64
    return false
  end

  # See if it's actually a masked token or not. In order to
  # deploy this code, we should be able to handle any unmasked
  # tokens that we've issued without error.

  if masked_token.length == AUTHENTICITY_TOKEN_LENGTH
    # This is actually an unmasked token. This is expected if
    # you have just upgraded to masked tokens, but should stop
    # happening shortly after installing this gem.
    compare_with_real_token masked_token, session

  elsif masked_token.length == AUTHENTICITY_TOKEN_LENGTH * 2
    csrf_token = unmask_token(masked_token)

    compare_with_real_token(csrf_token, session) ||
      valid_per_form_csrf_token?(csrf_token, session)
  else
    false # Token is malformed.
  end
end

यह देखने के लिए कि क्या यह सत्र टोकन से मेल खाता है, ग्राहक के नकाबपोश टोकन की जाँच करता है। अनिवार्य रूप से masked_authenticity_token का उलटा।

valid_per_form_csrf_token? (टोकन, सत्र) स्रोत दिखाएँ
# File actionpack/lib/action_controller/metal/request_forgery_protection.rb, line 376
def valid_per_form_csrf_token?(token, session) # :doc:
  if per_form_csrf_tokens
    correct_token = per_form_csrf_token(
      session,
      normalize_action_path(request.fullpath),
      request.request_method
    )

    ActiveSupport::SecurityUtils.fixed_length_secure_compare(token, correct_token)
  else
    false
  end
end
valid_request_origin? () स्रोत दिखाएं
# File actionpack/lib/action_controller/metal/request_forgery_protection.rb, line 430
def valid_request_origin? # :doc:
  if forgery_protection_origin_check
    # We accept blank origin headers because some user agents don't send it.
    raise InvalidAuthenticityToken, NULL_ORIGIN_MESSAGE if request.origin == "null"
    request.origin.nil? || request.origin == request.base_url
  else
    true
  end
end

मूल शीर्षलेख को देखकर अनुरोध एक ही मूल से उत्पन्न होता है या नहीं।

# File actionpack/lib/action_controller/metal/request_forgery_protection.rb, line 289
def verified_request? # :doc:
  !protect_against_forgery? || request.get? || request.head? ||
    (valid_request_origin? && any_authenticity_token_valid?)
end

यदि कोई अनुरोध सत्यापित है तो सही या गलत लौटाता है। चेकों:

  • क्या यह GET या HEAD अनुरोध है? GET सुरक्षित और आदर्श होना चाहिए

  • क्या form_authenticity_token, पैरामन्स से दिए गए टोकन मूल्य से मेल खाता है?

  • क्या X-CSRF-टोकन हेडर फॉर्म_ऑथेंटिसिटी_टोकन से मेल खाता है?

Ver_authenticity_token () स्रोत दिखाएं
# File actionpack/lib/action_controller/metal/request_forgery_protection.rb, line 227
def verify_authenticity_token # :doc:
  mark_for_same_origin_verification!

  if !verified_request?
    if logger && log_warning_on_csrf_failure
      if valid_request_origin?
        logger.warn "Can't verify CSRF token authenticity."
      else
        logger.warn "HTTP Origin header (#{request.origin}) didn't match request.base_url (#{request.base_url})"
      end
    end
    handle_unverified_request
  end
end

CSRF टोकन को सत्यापित करने के लिए उपयोग किया जाने वाला वास्तविक पहले_संक्रमण। इसे सीधे ओवरराइड न करें। इसके बजाय अपनी जालसाजी संरक्षण रणनीति प्रदान करें। यदि आप ओवरराइड करते हैं, तो आप समान-मूल <script> सत्यापन अक्षम करेंगे।

समान-मूल अनुरोध सत्यापन के कारण कौन से कार्य हैं, इसे चिह्नित करने के लिए protect_from_forgery घोषणा पर झुकें। अगर प्रोटेक्शन_फ्रोम_फॉर्गी को एक्शन पर सक्षम किया जाता है, तो यह पहले_हैंडने के बाद अपने सत्यापन के लिए झंडे को सत्यापित करता है कि जावास्क्रिप्ट प्रतिक्रियाएं XHR अनुरोधों के लिए हैं, यह सुनिश्चित करते हुए कि वे ब्राउज़र की समान मूल नीति का पालन करते हैं।

Ver_same_origin_request () स्रोत दिखाएं
# File actionpack/lib/action_controller/metal/request_forgery_protection.rb, line 257
def verify_same_origin_request # :doc:
  if marked_for_same_origin_verification? && non_xhr_javascript_response?
    if logger && log_warning_on_csrf_failure
      logger.warn CROSS_ORIGIN_JAVASCRIPT_WARNING
    end
    raise ActionController::InvalidCrossOriginRequest, CROSS_ORIGIN_JAVASCRIPT_WARNING
  end
end

अगर verify_authenticity_token चलाया गया था (यह दर्शाता है कि हमारे पास इस अनुरोध के लिए जालसाजी सुरक्षा सक्षम है) तो यह भी सत्यापित करें कि हम अनधिकृत क्रॉस-ऑरिजनल प्रतिक्रिया नहीं दे रहे हैं।

xor_byte_strings (s1, s2) स्रोत दिखाएं
# File actionpack/lib/action_controller/metal/request_forgery_protection.rb, line 403
def xor_byte_strings(s1, s2) # :doc:
  s2_bytes = s2.bytes
  s1.each_byte.with_index { |c1, i| s2_bytes[i] ^= c1 }
  s2_bytes.pack("C*")
end