2017-04-10 3 views
2

Ich habe eine Rails-API, die mit einem HTTP-only-Cookie authentifiziert ist, und als solches benötige ich CSRF-Schutz. Soweit ich das beurteilen kann, scheint es der Rails-Community vorzuziehen, jwt-Auth-Tokens lieber im lokalen Speicher als in einem Cookie zu speichern. Dies vermeidet die Notwendigkeit von CSRF, setzt Sie jedoch XSS zur Verfügung, weshalb wir uns dafür entschieden haben, cookies + csrf zu verwenden.So aktivieren Sie CSRF im Rails 5-API-Modus

Offenbar ist der CSRF-Schutz standardmäßig deaktiviert, da die Community lokalen Speicher bevorzugt. Ich versuche es mit begrenztem Erfolg zu ermöglichen. Hier ist, wie ich bin versucht, es zu handhaben:

module V1 
    class ApplicationController < ::ApplicationController 
    include Concerns::Authentication 
    include ActionController::RequestForgeryProtection 
    protect_from_forgery 

    protected 

    def handle_unverified_request 
     raise 'Invalid CSRF token' 
    end 

    after_action :set_csrf_cookie 

    def set_csrf_cookie 
     if current_user 
     cookies['X-CSRF-Token'] = form_authenticity_token 
     end 
    end 
    end 
end 

Auf der Client-Seite, ich kann sehen, dass das Token im Cookie kommt zurück. Wenn ich eine Anfrage mache, sehe ich auch, dass das Token im Header X-CSRF-Token vorhanden ist. Alles sieht soweit gut aus.

Die Methode verified_request? gibt jedoch false zurück, sodass handle_unverified_request aufgerufen wird. Beim Durchlaufen des Rails-Codes sehe ich, dass mein Token in request.x_csrf_token vorhanden ist, aber das Token scheint die Überprüfung nicht zu bestehen, wenn es mit der session überprüft wird. Eine Sache, die ich mich hier wundere, ist, wenn ich etwas aktivieren muss, um die session richtig funktionieren zu lassen, da ich weiß, dass die Sitzungsverwaltung nicht standardmäßig im API-Modus aktiviert ist. Aber wenn das der Fall wäre, würde ich erwarten, dass Versuche, auf das session Objekt zuzugreifen, explodieren, und das tun sie nicht, also bin ich mir nicht sicher.

Habe ich einen Fehler gemacht, oder muss ich eine andere Middleware einschalten? Oder brauche ich überhaupt einen anderen Ansatz, um CSRF mit diesem Schema zu ermöglichen?

Antwort

4

Ich weiß, dass dies ein Fall des Überdenkens des Problems war. Ich brauche wirklich nicht den Fälschungsschutz von Rails, um irgendetwas für mich zu tun, oder um den Wert gegen session zu überprüfen, weil der Wert meines Tokens bereits ein Cookie ist. Hier ist, wie ich es gelöst habe:

Zunächst setzt der Basis-Controller den csrf-Cookie. Dies würde für die Abmeldung oder irgendwelche öffentlichen Endpunkte übersprungen werden, wenn es welche gäbe.

module V1 
    class ApplicationController < ::ApplicationController 
    include Concerns::Authentication 
    include ActionController::RequestForgeryProtection 

    after_action :set_csrf_cookie 

    protected 

    def set_csrf_cookie 
     if current_user 
     cookies['X-CSRF-Token'] = form_authenticity_token 
     end 
    end 
    end 
end 

Dann erben meine authentifizierte Endpunkte von einem AuthenticatedController, die die Auth-Token und die csrf Token überprüft:

module V1 
    class AuthenticatedController < ApplicationController 
    before_action :authenticate! 

    def authenticate! 
     raise AuthenticationRequired unless current_user && csrf_token_valid? 
    end 

    rescue_from AuthenticationRequired do |e| 
     render json: { message: 'Authentication Required', code: :authentication_required }, status: 403 
    end 

    rescue_from AuthTokenExpired do |e| 
     render json: { message: 'Session Expired', code: :session_expired }, status: 403 
    end 

    private 

    def csrf_token_valid? 
     Rails.env != 'production' || request.headers['X-CSRF-Token'] === cookies['X-CSRF-Token'] 
    end 
    end 
end 

Hope this jemand anderes versucht, CSRF hilft in einer Rails-5-API + Cookies zu verwenden!

Verwandte Themen