Grundlegendes zum Rails-Authentizitätstoken


982

Ich habe einige Probleme mit dem Authentizitätstoken in Rails, wie ich es jetzt schon oft getan habe.

Aber ich möchte dieses Problem wirklich nicht einfach lösen und weitermachen. Ich würde das Authentizitätstoken wirklich gerne verstehen. Nun, meine Frage ist, haben Sie eine vollständige Informationsquelle zu diesem Thema oder würden Sie Ihre Zeit damit verbringen, dies hier ausführlich zu erklären?


7
Siehe auch: "Warum stellt Google während (1) auf seine JSON-Antwort vor?" stackoverflow.com/questions/2669690/…
Chloe

Antworten:


1462

Was geschieht

Wenn der Benutzer ein Formular zum Erstellen, Aktualisieren oder Zerstören einer Ressource anzeigt, erstellt die Rails-App einen Zufall authenticity_token, speichert dieses Token in der Sitzung und platziert es in einem ausgeblendeten Feld im Formular. Wenn der Benutzer das Formular sendet, sucht Rails nach dem authenticity_token, vergleicht es mit dem in der Sitzung gespeicherten und wenn es übereinstimmt, kann die Anforderung fortgesetzt werden.

Warum es passiert

Da das Authentizitätstoken in der Sitzung gespeichert ist, kann der Client seinen Wert nicht kennen. Dies verhindert, dass Personen Formulare an eine Rails-App senden, ohne das Formular in dieser App selbst anzuzeigen. Stellen Sie sich vor, Sie verwenden Dienst A, Sie haben sich beim Dienst angemeldet und alles ist in Ordnung. Stellen Sie sich nun vor, Sie haben Service B verwendet und ein Bild gesehen, das Ihnen gefällt, und auf das Bild gedrückt, um es zu vergrößern. Wenn bei Service B ein böser Code vorhanden war, sendet er möglicherweise eine Anfrage an Service A (bei dem Sie angemeldet sind) und fordert Sie auf, Ihr Konto zu löschen, indem Sie eine Anfrage an senden http://serviceA.com/close_account. Dies wird als CSRF (Cross Site Request Forgery) bezeichnet .

Wenn Dienst A Authentizitätstoken verwendet, ist dieser Angriffsvektor nicht mehr anwendbar, da die Anforderung von Dienst B nicht das richtige Authentizitätstoken enthalten würde und nicht fortgesetzt werden darf.

API-Dokumente beschreiben Details zum Meta-Tag:

Der CSRF-Schutz wird mit der protect_from_forgeryMethode aktiviert , die das Token überprüft und die Sitzung zurücksetzt, wenn sie nicht den Erwartungen entspricht. Ein Aufruf dieser Methode wird standardmäßig für neue Rails-Anwendungen generiert. Der Token-Parameter ist authenticity_tokenstandardmäßig benannt. Der Name und der Wert dieses Tokens müssen zu jedem Layout hinzugefügt werden, das Formulare durch Einfügen csrf_meta_tagsin den HTML-Kopf rendert .

Anmerkungen

Beachten Sie, dass Rails nur nicht idempotente Methoden überprüft (POST, PUT / PATCH und DELETE). GET-Anforderungen werden nicht auf Authentizitätstoken überprüft. Warum? Da in der HTTP-Spezifikation angegeben ist, dass GET-Anforderungen idempotent sind und keine Ressourcen auf dem Server erstellen, ändern oder zerstören sollten und die Anforderung idempotent sein sollte (wenn Sie denselben Befehl mehrmals ausführen, sollten Sie jedes Mal dasselbe Ergebnis erhalten).

Auch die eigentliche Implementierung ist, wie eingangs definiert, etwas komplizierter, um eine bessere Sicherheit zu gewährleisten. Rails gibt nicht bei jedem Formular das gleiche gespeicherte Token aus. Es wird auch nicht jedes Mal ein anderes Token generiert und gespeichert. Es generiert und speichert einen kryptografischen Hash in einer Sitzung und gibt jedes Mal, wenn eine Seite gerendert wird, neue kryptografische Token aus, die mit dem gespeicherten abgeglichen werden können. Siehe request_forgery_protection.rb .

Lektionen

Verwenden authenticity_tokenSie diese Option, um Ihre nicht idempotenten Methoden (POST, PUT / PATCH und DELETE) zu schützen. Stellen Sie außerdem sicher, dass keine GET-Anforderungen zulässig sind, die möglicherweise Ressourcen auf dem Server ändern könnten.


BEARBEITEN: Überprüfen Sie den Kommentar von @erturne bezüglich der idempotenten GET-Anforderungen. Er erklärt es besser als ich es hier getan habe.


25
@Faisal, ist es dann möglich, dass ein Angreifer einfach das 'versteckte' Element des Formulars für Service A liest / erfasst und das für den Benutzer generierte eindeutige Token erhält - vorausgesetzt, er hat Zugriff auf die vom Benutzer gestartete Sitzung erhalten für Service A?
Marcamillion

11
@marcamillion: Wenn jemand Ihre Sitzung bei Service A entführt hat, schützt Sie das Authentizitätstoken nicht. Der Entführer kann eine Anfrage stellen und fortfahren.
Faisal

12
@zabba: Rails löst eine ActionController :: InvalidAuthenticityToken-Ausnahme aus, wenn ein Formular ohne das richtige Token gesendet wird. Sie können die Ausnahme retten und die gewünschte Verarbeitung durchführen.
Faisal

5
re "Stellen Sie außerdem sicher, dass Sie keine GET-Anforderungen stellen, die möglicherweise Ressourcen auf dem Server ändern könnten." - Dies beinhaltet die Nichtverwendung von match () in Routen, die möglicherweise GET-Anforderungen an Controller-Aktionen ermöglichen könnten, die nur POSTs empfangen sollen
Steven Soroka

102
"... und die Anfrage sollte idempotent sein (wenn Sie denselben Befehl mehrmals ausführen, sollten Sie jedes Mal das gleiche Ergebnis erhalten)." Nur eine subtile Klarstellung hier. Sicher bedeutet keine Nebenwirkungen. Idempotent bedeutet den gleichen Nebeneffekt, unabhängig davon, wie oft ein Dienst aufgerufen wird. Alle sicheren Dienste sind von Natur aus idempotent, da keine Nebenwirkungen auftreten. Das mehrmalige Aufrufen von GET für eine Ressource zur aktuellen Zeit würde jedes Mal ein anderes Ergebnis zurückgeben, ist jedoch sicher (und daher idempotent).
Erturne

137

Das Authentizitätstoken ist so konzipiert, dass Sie wissen, dass Ihr Formular von Ihrer Website gesendet wird. Es wird von dem Computer generiert, auf dem es ausgeführt wird, und verfügt über eine eindeutige Kennung, die nur Ihr Computer kennen kann. Auf diese Weise werden standortübergreifende Fälschungsangriffe verhindert.

Wenn Sie nur Probleme mit Rails haben, die Ihren AJAX-Skriptzugriff verweigern, können Sie verwenden

<%= form_authenticity_token %>

um das richtige Token beim Erstellen Ihres Formulars zu generieren.

Weitere Informationen finden Sie in der Dokumentation .


88

Was ist CSRF?

Das Authentizitätstoken ist eine Gegenmaßnahme zur Cross-Site Request Forgery (CSRF). Was ist CSRF?

Auf diese Weise kann ein Angreifer möglicherweise Sitzungen entführen, ohne die Sitzungstoken zu kennen.

Szenario :

  • Besuchen Sie die Website Ihrer Bank und melden Sie sich an.
  • Besuchen Sie dann die Website des Angreifers (z. B. gesponserte Anzeige einer nicht vertrauenswürdigen Organisation).
  • Die Seite des Angreifers enthält ein Formular mit denselben Feldern wie das Formular "Überweisungsgelder" der Bank.
  • Der Angreifer kennt Ihre Kontoinformationen und verfügt über vorab ausgefüllte Formularfelder, mit denen Sie Geld von Ihrem Konto auf das Konto des Angreifers überweisen können.
  • Die Seite des Angreifers enthält Javascript, das das Formular an Ihre Bank sendet.
  • Wenn das Formular gesendet wird, enthält der Browser Ihre Cookies für die Bank-Website, einschließlich des Sitzungstokens.
  • Die Bank überweist Geld auf das Konto des Angreifers.
  • Das Formular kann sich in einem unsichtbaren Iframe befinden, sodass Sie nie wissen, dass der Angriff stattgefunden hat.
  • Dies wird als Cross-Site Request Forgery (CSRF) bezeichnet.

CSRF-Lösung :

  • Der Server kann Formulare markieren, die vom Server selbst stammen
  • Jedes Formular muss ein zusätzliches Authentifizierungstoken als verstecktes Feld enthalten.
  • Token muss unvorhersehbar sein (Angreifer können es nicht erraten).
  • Der Server stellt auf seinen Seiten ein gültiges Token in Formularen bereit.
  • Der Server überprüft das Token beim Versenden des Formulars und lehnt Formulare ohne das richtige Token ab.
  • Beispieltoken: Sitzungskennung, die mit dem geheimen Serverschlüssel verschlüsselt ist.
  • Rails generiert automatisch solche Token: Siehe das Eingabefeld authenticity_token in jeder Form.

1
Hier ist eine Version derselben Erklärung, die weniger genau, aber auch weniger abstrakt ist: stackoverflow.com/a/33829607/2810305
Lutz Prechelt

Ich bin mir nicht sicher, aber erlauben moderne Browser das Senden nicht idempotenter Anfragen (POST / PUT / DELETE) an eine andere Domain? Ich denke, es muss Schutz gegen solche Dinge im Browser selbst geben
DivideByZero

45

Minimales Angriffsbeispiel, das verhindert werden würde: CSRF

Auf meiner Website evil.comüberzeuge ich Sie, das folgende Formular einzureichen:

<form action="http://bank.com/transfer" method="post">
  <p><input type="hidden" name="to"      value="ciro"></p>
  <p><input type="hidden" name="ammount" value="100"></p>
  <p><button type="submit">CLICK TO GET PRIZE!!!</button></p>
</form>

Wenn Sie über Sitzungscookies bei Ihrer Bank angemeldet sind, werden die Cookies gesendet und die Überweisung erfolgt, ohne dass Sie es überhaupt wissen.

Hier kommt der CSRF-Token ins Spiel:

  • Mit der GET-Antwort, die das Formular zurückgegeben hat, sendet Rails einen sehr langen zufälligen versteckten Parameter
  • Wenn der Browser die POST-Anforderung stellt, sendet er den Parameter mit, und der Server akzeptiert ihn nur, wenn er übereinstimmt

Das Formular in einem authentischen Browser würde also folgendermaßen aussehen:

<form action="http://bank.com/transfer" method="post">
  <p><input type="hidden" name="authenticity_token" value="j/DcoJ2VZvr7vdf8CHKsvjdlDbmiizaOb5B8DMALg6s=" ></p>
  <p><input type="hidden" name="to"                 value="ciro"></p>
  <p><input type="hidden" name="ammount"            value="100"></p>
  <p><button type="submit">Send 100$ to Ciro.</button></p>
</form>

Daher würde mein Angriff fehlschlagen, da er den authenticity_tokenParameter nicht gesendet hat , und ich hätte ihn auf keinen Fall erraten können, da es sich um eine riesige Zufallszahl handelt.

Diese Verhinderungstechnik wird als Synchronizer-Token-Muster bezeichnet .

Gleiche Ursprungsrichtlinie

Was aber, wenn der Angreifer zwei Anfragen mit JavaScript gestellt hat, eine zum Lesen des Tokens und die zweite zum Übertragen?

Das Synchronizer-Token-Muster allein reicht nicht aus, um dies zu verhindern!

Hier kommt die Same Origin Policy zur Rettung, wie ich unter /security/8264/why-is-the-same-origin-policy-so-important/72569# erklärt habe 72569

Wie Rails die Token sendet

Behandelt bei: Rails: Wie funktioniert csrf_meta_tag?

Grundsätzlich:

  • HTML-Helfer form_tagfügen dem Formular gerne ein verstecktes Feld hinzu, wenn es sich nicht um ein GET-Formular handelt

  • AJAX wird automatisch von jquery-ujs behandelt , das das Token aus den metaElementen liest, die von csrf_meta_tags(in der Standardvorlage vorhanden) zu Ihrem Header hinzugefügt wurden , und es zu jeder gestellten Anforderung hinzufügt.

    uJS versucht auch, das Token in Formularen in veralteten zwischengespeicherten Fragmenten zu aktualisieren.

Andere Präventionsansätze


Vielen Dank, aber Ihr Argument, sich auf dieselbe Ursprungsrichtlinie zu verlassen, um nicht nur das CSRF-Token zuerst lesen zu können, scheint fehlerhaft. Wenn Sie also zuerst sagen, dass Sie zu einem anderen Ursprung POSTEN können, aber nicht daraus lesen können, scheint das seltsam, aber ich denke, das ist richtig, aber Sie könnten ein Bild- oder Skript-Tag mit einem Get-to-the-Page einfügen und einen Handler verknüpfen, um die Antwort zu analysieren und es ja bekommen?
bjm88

@ bjm88 injiziere das Skript wo? Auf Ihrer Site oder auf der angegriffenen Site? Wenn eine Website angegriffen wird, ist das Zulassen der Skriptinjektion eine bekannte Sicherheitslücke und verpfändet die Website effektiv. Jede Website muss dies durch Eingabesanierung bekämpfen. Bei Bildern sehe ich nicht, wie sie für einen Angriff verwendet werden können. Bei Angriffen auf eine Website: Sie können Ihren Browser so ändern, dass das Lesen möglich ist, und sich so nach Belieben automatisch verpfänden :-) Aber anständige Browser verhindern dies standardmäßig. Probieren Sie es aus.
Ciro Santilli 法轮功 病毒 审查 六四 事件 28

43

Das Authentizitätstoken wird verwendet, um Cross-Site Request Forgery-Angriffe (CSRF) zu verhindern. Um das Authentizitätstoken zu verstehen, müssen Sie zuerst CSRF-Angriffe verstehen.

CSRF

Angenommen, Sie sind der Autor von bank.com. Sie haben auf Ihrer Website ein Formular, mit dem Sie mit einer GET-Anfrage Geld auf ein anderes Konto überweisen können:

Geben Sie hier die Bildbeschreibung ein

Ein Hacker könnte einfach eine HTTP-Anfrage an den Server senden und sagen GET /transfer?amount=$1000000&account-to=999999, richtig?

Geben Sie hier die Bildbeschreibung ein

Falsch. Der Angriff der Hacker wird nicht funktionieren. Der Server wird grundsätzlich denken?

Huh? Wer ist dieser Typ, der versucht, eine Übertragung zu initiieren? Es ist nicht der Besitzer des Kontos, das ist sicher.

Woher weiß der Server das? Weil es kein session_idCookie gibt, das den Anforderer authentifiziert.

Wenn Sie sich mit Ihrem Benutzernamen und Passwort anmelden, setzt der Server ein session_idCookie in Ihrem Browser. Auf diese Weise müssen Sie nicht jede Anfrage mit Ihrem Benutzernamen und Passwort authentifizieren. Wenn Ihr Browser das session_idCookie sendet , weiß der Server:

Oh, das ist John Doe. Er hat sich vor 2,5 Minuten erfolgreich angemeldet. Er ist gut zu gehen.

Ein Hacker könnte denken:

Hmm. Eine normale HTTP-Anfrage funktioniert nicht, aber wenn ich diesen session_idCookie in die Hand bekommen könnte , wäre ich golden.

Der Browser des Benutzers hat eine Reihe von Cookies für die bank.comDomain gesetzt. Jedes Mal, wenn der Benutzer eine Anfrage an die bank.comDomain stellt, werden alle Cookies mitgesendet. Einschließlich des session_idCookies.

Wenn ein Hacker Sie dazu bringen könnte , die GET-Anfrage zu stellen, mit der Geld auf sein Konto überwiesen wird, wäre er erfolgreich. Wie konnte er dich dazu bringen? Mit Cross Site Request Forgery.

Eigentlich ist es ziemlich einfach. Der Hacker könnte Sie einfach dazu bringen, seine Website zu besuchen. Auf seiner Website könnte er das folgende Bild-Tag haben:

<img src="http://bank.com/transfer?amount=$1000000&account-to=999999">

Wenn der Browser des Benutzers auf dieses Bild-Tag stößt, sendet er eine GET-Anfrage an diese URL. Und da die Anfrage von seinem Browser kommt, werden alle damit verbundenen Cookies gesendet bank.com. Wenn sich der Benutzer kürzlich bei bank.com... angemeldet hat, wird das session_idCookie gesetzt und der Server wird denken, dass der Benutzer 1.000.000 USD auf das Konto 999999 überweisen wollte!

Geben Sie hier die Bildbeschreibung ein

Besuchen Sie nur keine gefährlichen Orte und es wird Ihnen gut gehen.

Das reicht nicht Was ist, wenn jemand dieses Bild auf Facebook veröffentlicht und es an Ihrer Wand erscheint? Was ist, wenn es in eine Site injiziert wird, die Sie mit einem XSS-Angriff besuchen?

Es ist nicht so schlecht. Nur GET-Anforderungen sind anfällig.

Nicht wahr. Ein Formular, das eine POST-Anforderung sendet, kann dynamisch generiert werden. Hier ist das Beispiel aus dem Rails-Handbuch zur Sicherheit :

<a href="http://www.harmless.com/" onclick="
  var f = document.createElement('form');
  f.style.display = 'none';
  this.parentNode.appendChild(f);
  f.method = 'POST';
  f.action = 'http://www.example.com/account/destroy';
  f.submit();
  return false;">To the harmless survey</a>

Authentizitätstoken

Wenn Sie ApplicationControllerdies haben:

protect_from_forgery with: :exception

Diese:

<%= form_tag do %>
  Form contents
<% end %>

Ist in diesem kompiliert:

<form accept-charset="UTF-8" action="/" method="post">
  <input name="utf8" type="hidden" value="&#x2713;" />
  <input name="authenticity_token" type="hidden" value="J7CBxfHalt49OSHp27hblqK20c9PgwJ108nDHX/8Cts=" />
  Form contents
</form>

Insbesondere wird folgendes erzeugt:

<input name="authenticity_token" type="hidden" value="J7CBxfHalt49OSHp27hblqK20c9PgwJ108nDHX/8Cts=" />

Wenn Rails zum Schutz vor CSRF-Angriffen das mit einer Anfrage gesendete Authentizitätstoken nicht sieht, wird die Anfrage nicht als sicher angesehen.

Woher soll ein Angreifer wissen, was dieser Token ist? Bei jeder Generierung des Formulars wird zufällig ein anderer Wert generiert:

Geben Sie hier die Bildbeschreibung ein

Ein Cross Site Scripting (XSS) -Angriff - so geht das. Aber das ist eine andere Sicherheitslücke für einen anderen Tag.



34

da Authenticity Tokenist so wichtig, und in Rails 3.0+ können Sie verwenden

 <%= token_tag nil %>

erschaffen

<input name="authenticity_token" type="hidden" value="token_value">

irgendwo


Das war hilfreich für mich. Ich habe tatsächlich versucht, XSSauf der Anmeldeseite nicht für schändliche Zwecke, sondern eine neue Sitzung mit einem vorab ausgefüllten Benutzernamen zu erstellen. Jetzt weiß ich, dass ich nur verwenden kann value="token_value".
Michael - Wo ist Clay Shirky

27

Beachten Sie, dass der Authenticity Token-Mechanismus zu Rennbedingungen führen kann, wenn Sie mehrere gleichzeitige Anforderungen vom selben Client haben. In dieser Situation kann Ihr Server mehrere Authentizitätstoken generieren, wenn es nur eines geben sollte, und der Client, der das frühere Token in einem Formular empfängt, schlägt bei seiner nächsten Anforderung fehl, da das Sitzungscookie-Token überschrieben wurde. Es gibt eine Beschreibung dieses Problems und eine nicht ganz triviale Lösung hier: http://www.paulbutcher.com/2007/05/race-conditions-in-rails-sessions-and-how-to-fix-them/


11

Methoden Wo authenticity_tokenerforderlich

authenticity_token ist erforderlich bei idempotenten Methoden wie Posten, Setzen und Löschen, da sich dempotente Methoden auf Daten auswirken.

Warum es erforderlich ist

Es ist erforderlich, um böse Handlungen zu verhindern. authenticity_token wird in einer Sitzung gespeichert. Wenn auf Webseiten ein Formular zum Erstellen oder Aktualisieren von Ressourcen erstellt wird, wird ein Authentizitätstoken in einem ausgeblendeten Feld gespeichert und mit dem Formular auf dem Server gesendet. Vor dem Ausführen der Aktion wird der vom Benutzer gesendete authenticity_token mit authenticity_tokenin der Sitzung gespeichert überprüft . Wenn authenticity_tokendies der Fall ist, wird der Prozess fortgesetzt, andernfalls werden keine Aktionen ausgeführt.


3
Ist es nicht das Gegenteil? GET ist idempotent, da sein Aufruf den Status des Systems nicht ändern sollte, wobei PUT POST- und DELETE-Verben KEINE idempotenten Verben sind, da sie den Systemstatus ändern. IE: Bei NICHT idempotenten Methoden ist authenticity_token erforderlich.
Jean-Théo

2
@ Jean-Daube, uma: idempotent bedeutet, dass bei zweimaliger Ausführung die Aktion nur einmal ausgeführt wird. GET, PUT und DELETE sind idempotent: w3.org/Protocols/rfc2616/rfc2616-sec9.html Die Schlüsseleigenschaft hier ist nicht idempotency, sondern ob sich die Methode ändert oder nicht die Daten, die als "sichere Methode" bezeichnet werden oder nicht.
Ciro Santilli 法轮功 at 审查 六四 事件 法轮功

6

Was ist ein Authentifizierungstoken?

Dies ist eine zufällige Zeichenfolge, die von der Rails-Anwendung verwendet wird, um sicherzustellen, dass der Benutzer eine Aktion von der App-Seite anfordert oder ausführt, nicht von einer anderen App oder Site.

Warum ist ein authentication_token erforderlich?

Zum Schutz Ihrer App oder Site vor Fälschung von standortübergreifenden Anfragen.

Wie füge ich einem Formular ein authentication_token hinzu?

Wenn Sie ein Formular mit dem Tag form_for generieren, wird automatisch ein Authentifizierungstoken hinzugefügt, das Sie verwenden können <%= csrf_meta_tag %>.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.