Rails 4 Authenticity Token

198

Ich habe an einer neuen Rails 4-App (unter Ruby 2.0.0-p0) gearbeitet, als ich auf Probleme mit Authentizitätstoken gestoßen bin.

Beim Schreiben eines Controllers, der auf json reagiert (mithilfe der respond_toKlassenmethode), kam ich zu der createAktion, bei der ich ActionController::InvalidAuthenticityTokenAusnahmen versuchte, als ich versuchte, einen Datensatz mit zu erstellen curl.

Ich habe dafür gesorgt, dass ich -H "Content-Type: application/json"die Daten eingestellt habe und mit, -d "<my data here>"aber immer noch kein Glück.

Ich habe versucht, denselben Controller mit Rails 3.2 (unter Ruby 1.9.3) zu schreiben, und habe keinerlei Probleme mit Authentizitätstoken. Ich habe mich umgesehen und festgestellt, dass in Rails 4 einige Änderungen an Authentizitätstoken vorgenommen wurden. Soweit ich weiß, werden diese nicht mehr automatisch in Formulare eingefügt. Ich nehme an, dass dies irgendwie Auswirkungen auf Nicht-HTML-Inhaltstypen hat.

Gibt es eine Möglichkeit, dies zu umgehen, ohne ein HTML-Formular anfordern zu müssen, das Authentizitätstoken zu entreißen und dann eine weitere Anfrage mit diesem Token zu stellen? Oder fehlt mir etwas, das völlig offensichtlich ist?

Bearbeiten: Ich habe gerade versucht, einen neuen Datensatz in einer neuen Rails 4-App mithilfe eines Gerüsts zu erstellen, ohne etwas zu ändern, und ich habe das gleiche Problem, also habe ich es wohl nicht getan.

alexcoco
quelle

Antworten:

277

Ich glaube, ich habe es gerade herausgefunden. Ich habe die (neue) Standardeinstellung geändert

protect_from_forgery with: :exception

zu

protect_from_forgery with: :null_session

gemäß dem Kommentar in ApplicationController.

# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.

Sie können den Unterschied erkennen, indem Sie in der Quelle nach request_forgery_protecton.rbden folgenden Zeilen suchen :

In Rails 3.2 :

# This is the method that defines the application behavior when a request is found to be unverified.
# By default, \Rails resets the session when it finds an unverified request.
def handle_unverified_request
  reset_session
end

In Schienen 4 :

def handle_unverified_request
  forgery_protection_strategy.new(self).handle_unverified_request
end

Welches wird das folgende nennen :

def handle_unverified_request
  raise ActionController::InvalidAuthenticityToken
end
alexcoco
quelle
20
Sie können die Option: with all together entfernen: null_session ist die Standardeinstellung: api.rubyonrails.org/classes/ActionController/…
Casey
6
Gibt es eine Möglichkeit, Ausnahmen für Nicht-JSON-Aufrufe und Nullsitzungen für JSON-Aufrufe (auch als API-Aufrufe bezeichnet) zu verwenden?
James McMahon
@JamesMcMahon Möglicherweise können Sie Ihre eigenen schreiben before_action , die das Format und die Überprüfung der Anforderung überprüft. Ich kenne keine eingebaute Methode, um Bedingungen festzulegen.
Alexcoco
1
In Rails 4.1.6 musste ich auch auf skip_before_action :verify_authenticity_tokendem Anwendungscontroller meiner API angeben , damit dies funktioniert.
Waseem
1
Sie sollten :verify_authenticy_tokenin Rails 4.2 nicht mehr deaktivieren müssen. Der Standardwert ist :null_session, dass Sie, wie der Name schon sagt, nur eine Anfrage ohne Sitzung erhalten. Sie können die Anforderung stattdessen über einen API-Schlüssel überprüfen.
Lobati
72

Anstatt den CSRF-Schutz zu deaktivieren, ist es besser, die folgende Codezeile in das Formular einzufügen

<%= tag(:input, :type => "hidden", :name => request_forgery_protection_token.to_s, :value => form_authenticity_token) %> 

Wenn Sie form_for oder form_tag verwenden, um das Formular zu generieren, wird automatisch die obige Codezeile in das Formular eingefügt

Xiaoboa
quelle
9
Dies ist ein guter Rat, wenn Sie ein Formular erstellen. Die Frage bezieht sich jedoch auf API-Aufrufe mit JSON.
James McMahon
1
Vielen Dank, dies beantwortete eine Frage, die ich zum Schreiben eines Codes von Hand hatte, während ich den Lenker benutzte!
David Routen
70

Das Hinzufügen der folgenden Zeile zum Formular hat bei mir funktioniert:

<%= hidden_field_tag :authenticity_token, form_authenticity_token %>
Carlos
quelle
12
trifft nicht wirklich auf API-Anrufe zu
Courtsimas
2
In meinem Fall verwende ich Rails4. Ich kann das Formular senden, indem ich auf die Schaltfläche "Senden" klicke. Aber wenn ich das Formular über JS-Code sende, tritt dieser Fehler auf. Und diese Antwort hat das Problem für mich behoben.
Chris.Zou
2
Für meine Rails 4.0.8 basierte App war es genug zu schreiben =token_tag niloder (in .erb)<%= token_tag nil %>
jmarceli
1
Sie scheinen die Authentifizierung zu deaktivieren, indem Sie das Token auf Null setzen?
Carlos
Ist es sicher, dies zu tun?
Angel Garcia
33

Ich denke nicht, dass es gut ist, den CSRF-Schutz generell zu deaktivieren, solange Sie nicht ausschließlich eine API implementieren.

Wenn Sie sich die Rails 4-API-Dokumentation für ActionController ansehen ich fest, dass Sie den Fälschungsschutz pro Controller oder pro Methodenbasis deaktivieren können.

Zum Beispiel, um den CSRF-Schutz für Methoden zu deaktivieren, die Sie verwenden können

class FooController < ApplicationController
  protect_from_forgery except: :index
Roamingthings
quelle
Dies hat es für mich in Rails 4 getan - Fehler, der nach dem Versuch des Löschens ausgelöst wurde. ^^
zero_cool
9

Kam über das gleiche Problem. Es wurde behoben, indem zu meinem Controller hinzugefügt wurde:

      skip_before_filter :verify_authenticity_token, if: :json_request?
user1756254
quelle
undefinierte Methode `json_request? ' für # <SettingsController: 0x000000030a54a8>, eine Idee?
Deano
Sie müssen dort eine Methode definieren wie: def json_request? request.format.json? Ende
Jai Kumar Rajput
7

Hast du versucht?

 protect_from_forgery with: :null_session, if: Proc.new {|c| c.request.format.json? }
zechtz
quelle
4

In diesem offiziellen Dokument wird erläutert, wie der Fälschungsschutz für die API ordnungsgemäß deaktiviert wird. Http://api.rubyonrails.org/classes/ActionController/RequestForgeryProtection.html

konung
quelle
1
Das stimmt, aber die Antwort stammt aus dem Jahr 2013 - und die Dinge ändern sich. Und während Ihre offiziell akzeptierte Antwort gut ist - mein Link gibt einfach einen besseren Überblick über das Thema
konung
2

Diese Funktionen wurden aus Sicherheits- und Fälschungsschutzgründen hinzugefügt.
Um Ihre Frage zu beantworten, finden Sie hier einige Eingaben. Sie können diese Zeilen nach dem Namen des Controllers hinzufügen.

Wie so,

class NameController < ApplicationController
    skip_before_action :verify_authenticity_token

Hier sind einige Zeilen für verschiedene Versionen von Schienen.

Schienen 3

skip_before_filter: verify_authenticity_token

Schienen 4 :

skip_before_action: verify_authenticity_token


Wenn Sie diese Sicherheitsfunktion für alle Controller-Routinen deaktivieren möchten , können Sie den Wert von protected_from_forgery in Ihrer Datei application_controller.rb in null_session ändern .

Wie so,

class ApplicationController < ActionController::Base
  protect_from_forgery with: :null_session
end
Kent Aguilar
quelle
1

Wenn Sie jQuery mit Rails verwenden, sollten Sie den Zugriff auf Methoden nicht zulassen, ohne das Authentizitätstoken zu überprüfen.

jquery-ujs kann die Token für Sie verwalten

Sie sollten es bereits als Teil des Edelsteins jquery-rail haben, müssen es jedoch möglicherweise in application.js mit aufnehmen

//= require jquery_ujs

Das ist alles was Sie brauchen - Ihr Ajax-Anruf sollte jetzt funktionieren

Weitere Informationen finden Sie unter: https://github.com/rails/jquery-ujs

user1555400
quelle
1

In authenticity_token: truedem Formular - Tag

Salma Gomaa
quelle
0

Wenn Sie Ihr eigenes HTML-Formular definieren, müssen Sie eine Authentifizierungs-Token-Zeichenfolge einschließen, die aus Sicherheitsgründen an den Controller gesendet werden soll. Wenn Sie den Rails Form Helper zum Generieren des Authentizitätstokens verwenden, wird das Formular wie folgt hinzugefügt.

<form accept-charset="UTF-8" action="/login/signin" method="post">
  <div style="display:none">
    <input name="utf8" type="hidden" value="&#x2713;" />
    <input name="authenticity_token" type="hidden" value="x37DrAAwyIIb7s+w2+AdoCR8cAJIpQhIetKRrPgG5VA=">
  </div>
    ...
</form>

Die Lösung des Problems besteht also darin, entweder das Feld authenticity_token hinzuzufügen oder Schienen von Helfern zu verwenden, anstatt die Sicherheit usw. zu gefährden.

amjad
quelle
1
Vielen Dank für Ihre Antwort, obwohl dies nicht die ursprüngliche Frage beantwortet. Die Frage zur Beantwortung von JSON-Anfragen wurde gestellt, aber Sie bieten eine Lösung für ein HTML-Formular von Grund auf neu. Wenn Sie JSON-Anforderungen stellen (Think API), senden Sie kein HTML-Formular und haben möglicherweise keinen einfachen Zugriff auf das Authentizitätstoken.
Alexcoco
es sei denn, der Inhalt der Anforderung ist tatsächlich JSON. In diesem Fall möchten Sie sie festlegen application/json.
Alexcoco
Ich verstehe, dass die Antwort nicht genau das ist, wonach Sie suchen. Der Zweck der entsprechenden Antwort besteht jedoch darin, Benutzern bei der Suche nach ähnlichen "Authentizitätsproblemen" zu helfen.
Amjad
Entschuldigung, ich habe versehentlich entfernt - "Sie können den Inhaltstyp festlegen: application / x-www-form-urlencoded mit der obigen Lösung".
Amjad
0

Alle meine Tests haben gut funktioniert. Aber aus irgendeinem Grund hatte ich meine Umgebungsvariable auf Nicht-Test gesetzt:

export RAILS_ENV=something_non_test

Ich habe vergessen, diese Variable zu deaktivieren, weshalb ich eine ActionController::InvalidAuthenticityTokenAusnahme bekam.

Nach dem Deaktivieren $RAILS_ENVfunktionierten meine Tests wieder.

mridula
quelle