ruby on rails - क्या यह रेल JSON प्रमाणीकरण API(Devise का उपयोग कर) सुरक्षित है?




ruby-on-rails security (2)

आप सीएसआरएफ को अक्षम नहीं करना चाहते हैं, मैंने पढ़ा है कि लोग सोचते हैं कि यह किसी कारण से जेएसओएन एपीआई पर लागू नहीं होता है, लेकिन यह एक गलतफहमी है। इसे सक्षम रखने के लिए, आप कुछ बदलाव करना चाहते हैं:

  • वहां सर्वर साइड आपके सत्र नियंत्रक के बाद एक_फिल्टर जोड़ें:

    after_filter :set_csrf_header, only: [:new, :create]
    
    protected
    
    def set_csrf_header
       response.headers['X-CSRF-Token'] = form_authenticity_token
    end
    

    यह एक टोकन उत्पन्न करेगा, इसे अपने सत्र में रखेगा और इसे चयनित कार्यों के लिए प्रतिक्रिया शीर्षलेख में कॉपी करेगा।

  • क्लाइंट साइड (आईओएस) आपको यह सुनिश्चित करने की ज़रूरत है कि दो चीजें जगह पर हों।

    • आपके क्लाइंट को इस हेडर के लिए सभी सर्वर प्रतिक्रियाओं को स्कैन करने की आवश्यकता है और इसे पारित होने पर इसे बनाए रखें।

      ... get ahold of response object
      // response may be a NSURLResponse object, so convert:
      NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)response;
      // grab token if present, make sure you have a config object to store it in
      NSString *token = [[httpResponse allHeaderFields] objectForKey:@"X-CSRF-Token"];
      if (token)
         [yourConfig setCsrfToken:token];
      
    • आखिरकार, आपके क्लाइंट को इस 'टोकन' अनुरोधों को इस टोकन को जोड़ने की आवश्यकता है:

      ... get ahold of your request object
      if (yourConfig.csrfToken && ![request.httpMethod isEqualToString:@"GET"])
        [request setValue:yourConfig.csrfToken forHTTPHeaderField:@"X-CSRF-Token"];
      

पहेली का अंतिम टुकड़ा यह समझना है कि जब तैयार करने के लिए लॉग इन करते हैं, तो दो बाद के सत्र / सीएसआरएफ टोकन का उपयोग किया जा रहा है। एक लॉगिन प्रवाह इस तरह दिखेगा:

GET /users/sign_in ->
  // new action is called, initial token is set
  // now send login form on callback:
  POST /users/sign_in <username, password> ->
    // create action called, token is reset
    // when login is successful, session and token are replaced 
    // and you can send authenticated requests

मेरा रेल ऐप प्रमाणीकरण के लिए डेविस का उपयोग करता है। इसमें एक बहन आईओएस ऐप है, और उपयोगकर्ता वेब ऐप के लिए उपयोग किए जाने वाले वही प्रमाण-पत्रों का उपयोग करके आईओएस ऐप में लॉग इन कर सकते हैं। तो मुझे प्रमाणीकरण के लिए किसी प्रकार की एपीआई चाहिए।

यहां पर इस तरह के बहुत सारे प्रश्न इस ट्यूटोरियल को इंगित करते हैं, लेकिन ऐसा लगता है कि token_authenticatable मॉड्यूल को बाद में डेविस से हटा दिया गया है और कुछ पंक्तियां त्रुटियों को फेंक देती हैं। (मैं डेविस 3.2.2 का उपयोग कर रहा हूं।) मैंने उस ट्यूटोरियल (और यह एक ) के आधार पर अपना खुद का रोल करने का प्रयास किया है, लेकिन मुझे इसमें 100% आत्मविश्वास नहीं है - मुझे लगता है कि मेरे पास कुछ ऐसा हो सकता है गलत समझा या याद किया।

सबसे पहले, इस user.rb की सलाह के बाद, मैंने अपने users तालिका में एक authentication_token टेक्स्ट विशेषता जोड़ा, और user.rb निम्नलिखित:

before_save :ensure_authentication_token

def ensure_authentication_token
  if authentication_token.blank?
    self.authentication_token = generate_authentication_token
  end
end

private

  def generate_authentication_token
    loop do
      token = Devise.friendly_token
      break token unless User.find_by(authentication_token: token)
    end
  end

तब मेरे पास निम्नलिखित नियंत्रक हैं:

api_controller.rb

class ApiController < ApplicationController
  respond_to :json
  skip_before_filter :authenticate_user!

  protected

  def user_params
    params[:user].permit(:email, :password, :password_confirmation)
  end
end

(ध्यान दें कि मेरे application_controller की लाइन before_filter :authenticate_user! )

एपीआई / sessions_controller.rb

class Api::SessionsController < Devise::RegistrationsController
  prepend_before_filter :require_no_authentication, :only => [:create ]

  before_filter :ensure_params_exist

  respond_to :json

  skip_before_filter :verify_authenticity_token

  def create
    build_resource
    resource = User.find_for_database_authentication(
      email: params[:user][:email]
    )
    return invalid_login_attempt unless resource

    if resource.valid_password?(params[:user][:password])
      sign_in("user", resource)
      render json: {
        success: true,
        auth_token: resource.authentication_token,
        email: resource.email
      }
      return
    end
    invalid_login_attempt
  end

  def destroy
    sign_out(resource_name)
  end

  protected

    def ensure_params_exist
      return unless params[:user].blank?
      render json: {
        success: false,
        message: "missing user parameter"
      }, status: 422
    end

    def invalid_login_attempt
      warden.custom_failure!
      render json: {
        success: false,
        message: "Error with your login or password"
      }, status: 401
    end
end

एपीआई / registrations_controller.rb

class Api::RegistrationsController < ApiController
  skip_before_filter :verify_authenticity_token

  def create
    user = User.new(user_params)
    if user.save
      render(
        json: Jbuilder.encode do |j|
          j.success true
          j.email user.email
          j.auth_token user.authentication_token
        end,
        status: 201
      )
      return
    else
      warden.custom_failure!
      render json: user.errors, status: 422
    end
  end
end

और config / routes.rb में :

  namespace :api, defaults: { format: "json" } do
    devise_for :users
  end

मैं अपनी गहराई से थोड़ा सा हूं और मुझे यकीन है कि यहां कुछ ऐसा है जो मेरा भविष्य स्वयं वापस देखेगा और क्रिंग करेगा (वहां आमतौर पर है)। कुछ iffy भागों:

सबसे पहले , आप देखेंगे कि Api::SessionsController नियंत्रक को Devise::RegistrationsController ApiController से विरासत मिली है जबकि Api::RegistrationsController ApiController से विरासत में ApiController (मेरे पास कुछ अन्य नियंत्रक भी हैं जैसे Api::EventsController < ApiController जो मेरे दूसरे के लिए अधिक मानक आरईएसटी सामान से Api::EventsController < ApiController मॉडल और डेविस के साथ अधिक संपर्क नहीं है।) यह एक बहुत बदसूरत व्यवस्था है, लेकिन मैं Api::RegistrationsController में आवश्यक तरीकों तक पहुंचने का एक और तरीका नहीं समझ पाया। उपरोक्त से जुड़े ट्यूटोरियल में लाइन include Devise::Controllers::InternalHelpers , लेकिन यह मॉड्यूल डेविस के हाल के संस्करणों में हटा दिया गया है।

दूसरा , मैंने लाइन skip_before_filter :verify_authentication_token साथ skip_before_filter :verify_authentication_token सुरक्षा अक्षम कर skip_before_filter :verify_authentication_token । मुझे इस बात का संदेह है कि यह एक अच्छा विचार है या नहीं - मुझे सलाह है कि जेएसओएन एपीआई सीएसआरएफ हमलों के लिए कमजोर हैं या नहीं, लेकिन यह लाइन एकमात्र तरीका है जिससे मैं काम करने के लिए काम कर सकता हूं।

तीसरा , मैं यह सुनिश्चित करना चाहता हूं कि उपयोगकर्ता समझने के बाद मैं समझता हूं कि प्रमाणीकरण कैसे काम करता है। कहें कि मेरे पास एक एपीआई कॉल GET /api/friends जो वर्तमान उपयोगकर्ता के दोस्तों की एक सूची देता है। जैसा कि मैं इसे समझता हूं, आईओएस ऐप को डेटाबेस से उपयोगकर्ता का authentication_token प्राप्त करना होगा (जो प्रत्येक उपयोगकर्ता के लिए एक निश्चित मान है जो कभी नहीं बदलता ??), फिर इसे प्रत्येक अनुरोध के साथ एक param के रूप में सबमिट करें, उदाहरण के लिए GET /api/friends?authentication_token=abcdefgh1234 , तो मेरा Api::FriendsController current_user प्राप्त करने के लिए User.find_by(authentication_token: params[:authentication_token]) Api::FriendsController User.find_by(authentication_token: params[:authentication_token]) जैसे कुछ कर सकता है। क्या यह वास्तव में यह आसान है, या क्या मुझे कुछ याद आ रहा है?

ऐसे में किसी भी व्यक्ति के लिए जो इस विशाल प्रश्न के अंत तक सभी तरह से पढ़ने में कामयाब रहा है, आपके समय के लिए धन्यवाद! संक्षेपित करते हुए:

  1. क्या यह लॉगिन सिस्टम सुरक्षित है? या क्या ऐसा कुछ है जिसे मैंने अनदेखा किया है या गलत समझा है, उदाहरण के लिए जब सीएसआरएफ हमलों की बात आती है?
  2. उपयोगकर्ताओं द्वारा सही तरीके से साइन इन किए जाने के बाद अनुरोधों को प्रमाणित करने की मेरी समझ क्या है? (ऊपर "तीसरा ..." देखें।)
  3. क्या इस कोड को साफ किया जा सकता है या अच्छा बनाया जा सकता है? विशेष रूप से एक नियंत्रक होने का बदसूरत डिज़ाइन Devise::RegistrationsController कंट्रोलर और अन्य ApiController से प्राप्त ApiController

धन्यवाद!


आपका उदाहरण डेविस ब्लॉग से कोड की नकल करने लगता है - https://gist.github.com/josevalim/fb706b1e933ef01e4fb6

जैसा कि उस पोस्ट में उल्लिखित है, आप इसे विकल्प 1 के समान कर रहे हैं, जो वे कहते हैं कि असुरक्षित विकल्प है। मुझे लगता है कि कुंजी यह है कि जब भी उपयोगकर्ता सहेजा जाता है तो आप प्रमाणीकरण टोकन को रीसेट करना नहीं चाहते हैं। मुझे लगता है कि टोकन स्पष्ट रूप से बनाया जाना चाहिए (एपीआई में किसी प्रकार के टोकन कंट्रोलर द्वारा) और समय-समय पर समाप्त होना चाहिए।

आप देखेंगे कि मैं कहता हूं कि 'मुझे लगता है' (जहां तक ​​मैं कह सकता हूं) इस पर कोई और जानकारी नहीं है।





devise