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])
जैसे कुछ कर सकता है। क्या यह वास्तव में यह आसान है, या क्या मुझे कुछ याद आ रहा है?
ऐसे में किसी भी व्यक्ति के लिए जो इस विशाल प्रश्न के अंत तक सभी तरह से पढ़ने में कामयाब रहा है, आपके समय के लिए धन्यवाद! संक्षेपित करते हुए:
- क्या यह लॉगिन सिस्टम सुरक्षित है? या क्या ऐसा कुछ है जिसे मैंने अनदेखा किया है या गलत समझा है, उदाहरण के लिए जब सीएसआरएफ हमलों की बात आती है?
- उपयोगकर्ताओं द्वारा सही तरीके से साइन इन किए जाने के बाद अनुरोधों को प्रमाणित करने की मेरी समझ क्या है? (ऊपर "तीसरा ..." देखें।)
- क्या इस कोड को साफ किया जा सकता है या अच्छा बनाया जा सकता है? विशेष रूप से एक नियंत्रक होने का बदसूरत डिज़ाइन
Devise::RegistrationsController
कंट्रोलर और अन्यApiController
से प्राप्तApiController
।
धन्यवाद!
आपका उदाहरण डेविस ब्लॉग से कोड की नकल करने लगता है - https://gist.github.com/josevalim/fb706b1e933ef01e4fb6
जैसा कि उस पोस्ट में उल्लिखित है, आप इसे विकल्प 1 के समान कर रहे हैं, जो वे कहते हैं कि असुरक्षित विकल्प है। मुझे लगता है कि कुंजी यह है कि जब भी उपयोगकर्ता सहेजा जाता है तो आप प्रमाणीकरण टोकन को रीसेट करना नहीं चाहते हैं। मुझे लगता है कि टोकन स्पष्ट रूप से बनाया जाना चाहिए (एपीआई में किसी प्रकार के टोकन कंट्रोलर द्वारा) और समय-समय पर समाप्त होना चाहिए।
आप देखेंगे कि मैं कहता हूं कि 'मुझे लगता है' (जहां तक मैं कह सकता हूं) इस पर कोई और जानकारी नहीं है।