SORU
23 Aralık 2013, PAZARTESİ


Bu Raylar API kimlik (Vasiyetle kullanarak) güvenli JSON mi?

Benim Raylar app kimlik doğrulama için Hazırlamak kullanır. Kardeş iOS uygulaması, kullanıcıların iOS uygulaması web uygulaması için kullandığınız aynı kimlik bilgilerini kullanarak giriş yapabilirsiniz. Kimlik doğrulama için API bir tür istiyorum.

Çok benzer sorular burada işaret etmek this tutorial ama sanırım güncel olarak token_authenticatable modül vardır beri çıkarılması Hazırlamak ve bazı çizgiler atmak hata. (3.2.2. Vasiyet) kullanıyorum Yaptım çalıştı rulo benim kendi dayandığı öğretici (this one), ama ben değilim 100% emin - hissediyorum gibi olabilir bir şey var yanlış veya cevapsız.

Öncelikle, this gist, tavsiyelerini dinlemek ekledim authentication_token metin users masam, ve user.rb aşağıdaki nitelik:

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

Aşağıdaki denetleyicileri var:

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

(Benim not application_controller satır before_filter :authenticate_user!.)

/sessions_controller apı.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 apı.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

Ve/config yolları.rb:

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

Derinliğimi ben ve gelecekteki ben geriye dönüp baktığımda, yalakalık (genellikle yoktur) burada bir şey var eminim. Bazı şüpheli parçalar:

Önceliklegöreceksiniz, dikkat edin Api::SessionsController miras Devise::RegistrationsController oysa Api::RegistrationsController miras ApiController (bir de diğer denetleyicileri gibi Api::EventsController < ApiController hangi anlaşma ile daha standart KALAN şeyler için benim diğer modeller ve pek temas ile Sağlanır.) Bu çok çirkin bir düzenlemedir, ama ihtiyacım olan yöntemleri erişim Api::RegistrationsController girmenin başka bir yolunu bulamadım. Öğretici ben yukarıda bağlantılı include Devise::Controllers::InternalHelpers ama bu modül Hazırlamak daha yeni sürümlerinde kaldırılmış gibi görünüyor çizgi vardır.

İkincisiÇizgi ile koruma skip_before_filter :verify_authentication_token CSRF devre dışı bıraktım. Ben benim kuşkularım olsun bu çok iyi bir fikir olduğunu - görüyorum ki bir sürü conflicting hard to understand nasihat olsun JSON API savunmasız CSRF saldırıları - ama ekleme satırı tek yolu bulabilirim lanet şey.

ÜçüncüsüBir kullanıcı imzaladı sonra kimlik doğrulaması nasıl çalıştığını anlamak emin olmak istiyorum. Geçerli kullanıcının arkadaş listesini döndüren 28* *bir API çağrısı var. Anladığım kadarıyla, iOS app kullanıcı authentication_token almak için veritabanından olurdu hiç değişmiyor her kullanıcı için sabit bir değer olan (??), sonra her istekle birlikte bir parametre olarak göndermek, GET /api/friends?authentication_token=abcdefgh1234 örneğin, Api::FriendsController User.find_by(authentication_token: params[:authentication_token]) gibi bir şey örnein almak için yapabilir. Gerçekten bu kadar basit mi, ya da ben bir şey eksik?

Bu dev sorunun sonuna kadar okumayı başardım olan herkes için, zaman ayırdığınız için teşekkürler! Özetlemek gerekirse:

  1. Bu giriş sistemi güvenli mi?Ya gözden kaçan ya da yanlış yaptığım bir şey var CSRF saldırılarına gelince, örneğin?
  2. Kullanıcılar doğru imzalandığında istekleri kimlik doğrulaması için nasıl benim anlayış?("Üçüncüsü..." yukarıda.)
  3. Bu kod temizlenebilir ya da iyi yapılmış bir yolu var mı?Özellikle bir denetleyici olması çirkin tasarım ApiController 33 *ve başkalarından devralmak.

Teşekkürler!

CEVAP
29 Aralık 2013, Pazar


CSRF devre dışı bırakmak istemezsin, insanlar nedense JSON API için geçerli değil sanırım öyle okudum, ama bu bir yanlış anlaşılma. Bu etkin tutmak için, bir kaç değişiklik yapmak istiyorum:

  • orada sunucu tarafı oturumları denetleyicisi için bir after_filter ekleyin:

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

    Bu bir simge oluşturur, seans koymak ve seçilen eylemler için yanıt Başlığı kopyalayın.

  • istemci tarafında (iOS) iki şeyin yerinde olduğundan emin olun.

    • müvekkiliniz bu başlık için tüm sunucu yanıt tarama ve birlikte geçirilen zaman korumak gerekiyor.

      ... 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];
      
    • son olarak, istemci tüm bu simge eklemek gerekiyor 'non' istekleri gönderir:

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

Bulmacanın son parçası içinde bulmak için günlük/csrf belirteçleri iki sonraki seans kullanıldığını anlamak için. Giriş akışı şu şekilde görünecektir:

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

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • FamilyFeud

    FamilyFeud

    22 AĞUSTOS 2006
  • fufko

    fufko

    27 ŞUBAT 2006
  • Kyler Briskey

    Kyler Briske

    20 ŞUBAT 2011