Ruby on Rails 5.2 - ActionController::HttpAuthentication::Digest

मॉड्यूल एक्शनकंट्रोलर :: HttpAuthentication :: डाइजेस्ट




ruby

मॉड्यूल एक्शनकंट्रोलर :: HttpAuthentication :: डाइजेस्ट

HTTP Digest प्रमाणीकरण करना आसान बनाता है।

सरल डाइजेस्ट उदाहरण

require 'digest/md5'
class PostsController < ApplicationController
  REALM = "SuperSecret"
  USERS = {"dhh" => "secret", #plain text password
           "dap" => Digest::MD5.hexdigest(["dap",REALM,"secret"].join(":"))}  #ha1 digest password

  before_action :authenticate, except: [:index]

  def index
    render plain: "Everyone can see me!"
  end

  def edit
    render plain: "I'm only accessible if you know the password"
  end

  private
    def authenticate
      authenticate_or_request_with_http_digest(REALM) do |username|
        USERS[username]
      end
    end
end

टिप्पणियाँ

authenticate_or_request_with_http_digest or_request_with_http_digest उपयोगकर्ता के पासवर्ड या ha1 डाइजेस्ट हैश को वापस करना चाहिए ताकि फ्रेमवर्क उपयोगकर्ता की साख की जांच करने के लिए उचित रूप से हैश कर सके। nil वापस करने से प्रमाणीकरण विफल हो जाएगा।

स्टोर करना ha1 हैश: MD5 (उपयोगकर्ता नाम: दायरे: पासवर्ड), एक सादा पासवर्ड को संग्रहीत करने से बेहतर है। यदि पासवर्ड फ़ाइल या डेटाबेस से समझौता किया जाता है, तो हमलावर इस realm में उपयोगकर्ता के रूप में प्रमाणित करने के लिए ha1 हैश का उपयोग करने में सक्षम होगा, लेकिन अन्य साइटों पर उपयोग करने का प्रयास करने के लिए उपयोगकर्ता का पासवर्ड नहीं होगा।

दुर्लभ उदाहरणों में, वेब सर्वर या फ्रंट परदे के पीछे से हेडराइजेशन हेडर आपके आवेदन पर पहुंचने से पहले। आप सभी पर्यावरण चर को लॉग करके और HTTP_AUTHORIZATION, अन्य लोगों के लिए जाँच कर इस स्थिति को डीबग कर सकते हैं।

सार्वजनिक प्रवृत्ति के तरीके

प्रमाणीकृत करें (अनुरोध, दायरे, और पासवर्ड_प्रक्रिया) स्रोत दिखाएं
# File actionpack/lib/action_controller/metal/http_authentication.rb, line 197
def authenticate(request, realm, &password_procedure)
  request.authorization && validate_digest_response(request, realm, &password_procedure)
end

एक वैध प्रतिक्रिया पर गलत रिटर्न, सच अन्यथा

प्रमाणीकरण_हाइडर (नियंत्रक, दायरे) स्रोत दिखाएँ
# File actionpack/lib/action_controller/metal/http_authentication.rb, line 255
def authentication_header(controller, realm)
  secret_key = secret_token(controller.request)
  nonce = self.nonce(secret_key)
  opaque = opaque(secret_key)
  controller.headers["WWW-Authenticate"] = %(Digest realm="#{realm}", qop="auth", algorithm=MD5, nonce="#{nonce}", opaque="#{opaque}")
end
प्रमाणीकरण_ क्रेक (नियंत्रक, दायरे, संदेश = शून्य) स्रोत दिखाएँ
# File actionpack/lib/action_controller/metal/http_authentication.rb, line 262
def authentication_request(controller, realm, message = nil)
  message ||= "HTTP Digest: Access denied.\n"
  authentication_header(controller, realm)
  controller.status = 401
  controller.response_body = message
end
decode_credentials (शीर्ष लेख) स्रोत दिखाएं
# File actionpack/lib/action_controller/metal/http_authentication.rb, line 248
def decode_credentials(header)
  ActiveSupport::HashWithIndifferentAccess[header.to_s.gsub(/^Digest\s+/, "").split(",").map do |pair|
    key, value = pair.split("=", 2)
    [key.strip, value.to_s.gsub(/^"|"$/, "").delete("'")]
  end]
end
decode_credentials_header (अनुरोध) स्रोत दिखाएं
# File actionpack/lib/action_controller/metal/http_authentication.rb, line 244
def decode_credentials_header(request)
  decode_credentials(request.authorization)
end
encode_credentials (http_method, क्रेडेंशियल्स, पासवर्ड, पासवर्ड_is_ha1) स्रोत दिखाएँ
# File actionpack/lib/action_controller/metal/http_authentication.rb, line 239
def encode_credentials(http_method, credentials, password, password_is_ha1)
  credentials[:response] = expected_response(http_method, credentials[:uri], credentials, password, password_is_ha1)
  "Digest " + credentials.sort_by { |x| x[0].to_s }.map { |v| "#{v[0]}='#{v[1]}'" }.join(", ")
end
अपेक्षित_आदर्श (http_method, uri, क्रेडेंशियल, पासवर्ड, पासवर्ड_is_ha1 = सत्य) दिखाएँ स्रोत
# File actionpack/lib/action_controller/metal/http_authentication.rb, line 229
def expected_response(http_method, uri, credentials, password, password_is_ha1 = true)
  ha1 = password_is_ha1 ? password : ha1(credentials, password)
  ha2 = ::Digest::MD5.hexdigest([http_method.to_s.upcase, uri].join(":"))
  ::Digest::MD5.hexdigest([ha1, credentials[:nonce], credentials[:nc], credentials[:cnonce], credentials[:qop], ha2].join(":"))
end

http_method अनुरोध के लिए अपेक्षित प्रतिक्रिया को डीकोड credentials गए credentials और अपेक्षित password साथ http_method है वैकल्पिक पैरामीटर password_is_ha1 डिफ़ॉल्ट रूप से true सेट होता true , क्योंकि सादा-पाठ पासवर्ड के बजाय ha1 डाइजेस्ट को स्टोर करने के लिए सबसे अच्छा अभ्यास है।

ha1 (क्रेडेंशियल्स, पासवर्ड) स्रोत दिखाएं
# File actionpack/lib/action_controller/metal/http_authentication.rb, line 235
def ha1(credentials, password)
  ::Digest::MD5.hexdigest([credentials[:username], credentials[:realm], password].join(":"))
end
nonce (secret_key, time = Time.now) स्रोत दिखाएं
# File actionpack/lib/action_controller/metal/http_authentication.rb, line 307
def nonce(secret_key, time = Time.now)
  t = time.to_i
  hashed = [t, secret_key]
  digest = ::Digest::MD5.hexdigest(hashed.join(":"))
  ::Base64.strict_encode64("#{t}:#{digest}")
end

केवल एक बार उपयोग किए जाने वाले मान उत्पन्न करने के लिए समय के आधार पर एमडी 5 डाइजेस्ट का उपयोग करता है।

एक सर्वर-निर्दिष्ट डेटा स्ट्रिंग जिसे विशिष्ट रूप से 401 रिस्पॉन्स किए जाने पर हर बार उत्पन्न किया जाना चाहिए। यह अनुशंसा की जाती है कि यह स्ट्रिंग बेस 64 या हेक्साडेसिमल डेटा हो। विशेष रूप से, चूंकि स्ट्रिंग को हेडर लाइनों में उद्धृत स्ट्रिंग के रूप में पारित किया जाता है, दोहरे-उद्धरण वर्ण की अनुमति नहीं है।

गैर की सामग्री कार्यान्वयन पर निर्भर है। कार्यान्वयन की गुणवत्ता एक अच्छे विकल्प पर निर्भर करती है। उदाहरण के लिए, एक नॉन बेस 64 एन्कोडिंग के रूप में निर्मित किया जा सकता है

time-stamp H(time-stamp ":" ETag ":" private-key)

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

एक कार्यान्वयन एक पहले से इस्तेमाल किए गए गैर-ग्रहण या पहले से इस्तेमाल किए गए पाचन को स्वीकार नहीं करने के लिए चुन सकता है, ताकि एक पुनरावृत्ति हमले से बचा जा सके। या, एक कार्यान्वयन POST, PUT, या PATCH अनुरोधों और GET अनुरोधों के लिए एक समय-मोहर के लिए एक-बार के गैर-रियायतों या पचड़ों का उपयोग करना चुन सकता है। शामिल मुद्दों पर अधिक जानकारी के लिए इस दस्तावेज़ की धारा 4 देखें।

गैर ग्राहक के लिए अपारदर्शी है। Time रचना, और परियोजना के निर्माण पर उत्पन्न रेल सत्र रहस्य से गुप्त कुंजी के साथ Time हैश। यह सुनिश्चित करता है कि ग्राहक द्वारा समय को संशोधित नहीं किया जा सकता है।

अपारदर्शी (secret_key) स्रोत दिखाएँ
# File actionpack/lib/action_controller/metal/http_authentication.rb, line 326
def opaque(secret_key)
  ::Digest::MD5.hexdigest(secret_key)
end

गुप्त कुंजी के पाचन पर आधारित अपारदर्शी

secret_token (अनुरोध) स्रोत दिखाएँ
# File actionpack/lib/action_controller/metal/http_authentication.rb, line 269
def secret_token(request)
  key_generator  = request.key_generator
  http_auth_salt = request.http_auth_salt
  key_generator.generate_key(http_auth_salt)
end
validate_digest_response (अनुरोध, दायरे, और पासवर्ड_प्रक्रिया) स्रोत दिखाएं
# File actionpack/lib/action_controller/metal/http_authentication.rb, line 204
def validate_digest_response(request, realm, &password_procedure)
  secret_key  = secret_token(request)
  credentials = decode_credentials_header(request)
  valid_nonce = validate_nonce(secret_key, request, credentials[:nonce])

  if valid_nonce && realm == credentials[:realm] && opaque(secret_key) == credentials[:opaque]
    password = password_procedure.call(credentials[:username])
    return false unless password

    method = request.get_header("rack.methodoverride.original_method") || request.get_header("REQUEST_METHOD")
    uri    = credentials[:uri]

    [true, false].any? do |trailing_question_mark|
      [true, false].any? do |password_is_ha1|
        _uri = trailing_question_mark ? uri + "?" : uri
        expected = expected_response(method, _uri, credentials, password, password_is_ha1)
        expected == credentials[:response]
      end
    end
  end
end

जब तक अनुरोध क्रेडेंशियल प्रतिक्रिया मूल्य अपेक्षित मूल्य से मेल नहीं खाता है, तब तक गलत रिटर्न। पहले पासवर्ड को ha1 डाइजेस्ट पासवर्ड के रूप में आज़माएँ। यदि यह विफल रहता है, तो इसे एक सादे पाठ पासवर्ड के रूप में आज़माएं।

validate_nonce (secret_key, request, value, seconds_to_timeout = 5 * 60) स्रोत दिखाएं
# File actionpack/lib/action_controller/metal/http_authentication.rb, line 319
def validate_nonce(secret_key, request, value, seconds_to_timeout = 5 * 60)
  return false if value.nil?
  t = ::Base64.decode64(value).split(":").first.to_i
  nonce(secret_key, t) == value && (t - Time.now.to_i).abs <= seconds_to_timeout
end

अनुरोध एक PATCH, PUT, या POST है, और यदि क्लाइंट एक ब्राउज़र या वेब सेवा है, इस पर निर्भर करते हुए एक छोटा टाइमआउट चाहते हैं। बहुत कम हो सकता है अगर बासी निर्देश लागू किया जाता है। यह एक उपयोगकर्ता को अपने उपयोगकर्ता नाम और पासवर्ड के लिए फिर से उपयोगकर्ता को संकेत दिए बिना नए गैर का उपयोग करने की अनुमति देगा।