Ist diese Rails-JSON-Authentifizierungs-API (mit Devise) sicher?

Meiner Rails-app nutzt Entwickeln, die für die Authentifizierung. Es hat eine Schwester-iOS-app, und Benutzer können sich in der iOS-app mit den gleichen Anmeldeinformationen, die Sie verwenden für die web-app. Also brauche ich eine Art API für die Authentifizierung.

Viele ähnliche Fragen hier dieses tutorialaber es scheint zu sein, out-of-date, wie die token_authenticatable Modul wurde inzwischen entfernt Erarbeiten und einige der Linien werfen Fehler. (Ich bin mit Entwickeln 3.2.2.) Ich habe versucht zu Rollen, meine eigene, basierend auf diesem tutorial (und diese eine), aber ich bin mir nicht 100% sicher drin - ich fühle mich wie es sein kann, etwas habe ich falsch verstanden oder verpasst.

Erstens, im Anschluss an die Beratung der diese gistich habe eine authentication_token text-Attribut, um meine users Tisch, und die folgenden 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

Dann habe ich folgende Controller:

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

(Beachten Sie, dass meine application_controller hat die Linie before_filter :authenticate_user!.)

api/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

api/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

Und in config/routes.rb:

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

Ich bin aus meiner Tiefe ein bisschen und ich bin sicher, es gibt hier etwas, das meine Zukunft Aussehen wird, wieder auf und kriechen (gibt es normalerweise der Fall ist). Einige iffy Teile:

Erstenswerden Sie feststellen, dass Api::SessionsController erbt von Devise::RegistrationsController in der Erwägung, dass Api::RegistrationsController erbt von ApiController (ich habe auch einige andere Controller wie Api::EventsController < ApiController die sich mit der mehr standard-REST Kram für meine anderen Modelle und haben nicht viel Kontakt mit Entwickeln.) Dies ist eine ziemlich unschöne Anordnung, aber ich konnte nicht herausfinden, ein anderer Weg, um Zugriff auf die Methoden, die ich brauche in Api::RegistrationsController. Das tutorial habe ich im Zusammenhang mit oben hat die Linie include Devise::Controllers::InternalHelpersaber dieses Modul scheint entfernt worden, die in neueren Versionen von Entwickeln.

Zweitens habe ich deaktiviert CSRF-Schutz mit der Linie skip_before_filter :verify_authentication_token. Ich habe meine Zweifel, ob das eine gute Idee ist - ich sehe eine Menge von widersprüchliche oder schwer zu verstehen Beratung darüber, ob JSON-APIs sind anfällig für CSRF-Attacken - aber das hinzufügen dieser Zeile war der einzige Weg, ich könnte das verdammte Ding zu arbeiten.

Drittensmöchte ich sicherstellen, dass ich verstehe, wie die Authentifizierung funktioniert, sobald ein Benutzer angemeldet ist. Sagen, ich habe einen API-Aufruf GET /api/friends gibt eine Liste der aktuellen Benutzer, die Freunde. Wie ich es verstehe, ist die iOS-app hätte, um die Benutzer authentication_token aus der Datenbank (das ist ein fester Wert für jeden Benutzer, der sich niemals ändert??), dann reichen Sie es als param zusammen mit jeder Anforderung, z.B. GET /api/friends?authentication_token=abcdefgh1234dann meine Api::FriendsController etwas tun könnte wie User.find_by(authentication_token: params[:authentication_token]) um die current_user. Ist es wirklich so einfach, oder bin ich etwas fehlt?

Also für jeden, der es geschafft hat zu Lesen, den ganzen Weg bis zum Ende dieser Mammut-Frage, vielen Dank für Ihre Zeit! Zusammenfassend:

  1. Ist dieses login system sicher? Oder gibt es so etwas habe ich übersehen oder missverstanden, z.B. wenn es um CSRF-Angriffe?
  2. Ist mein Verständnis für die Anforderungen authentifizieren, wenn Benutzer angemeldet sind, richtig? (Siehe "drittens..." oben).
  3. Gibt es eine Möglichkeit, diesen code bereinigt werden können oder schöner gemacht? Besonders das hässliche design von one controller Erben von Devise::RegistrationsController und die anderen von ApiController.

Dank!

InformationsquelleAutor der Frage GMA | 2013-12-23

Schreibe einen Kommentar