Cross Site Request Forgery (CSRF) wird normalerweise mit einer der folgenden Methoden verhindert:
- Referer prüfen - RESTful aber unzuverlässig
- Token in Formular einfügen und Token in der Serversitzung speichern - nicht wirklich RESTful
- kryptische einmalige URIs - aus dem gleichen Grund wie Token nicht RESTful
- Kennwort manuell für diese Anforderung senden (nicht das zwischengespeicherte Kennwort, das bei der HTTP-Authentifizierung verwendet wird) - RESTful, aber nicht praktisch
Meine Idee ist es, ein Benutzergeheimnis, eine kryptische, aber statische Formular-ID und JavaScript zu verwenden, um Token zu generieren.
<form method="POST" action="/someresource" id="7099879082361234103">
<input type="hidden" name="token" value="generateToken(...)">
...
</form>
GET /usersecret/john_doe
vom JavaScript vom authentifizierten Benutzer abgerufen.- Antwort:
OK 89070135420357234586534346
Dieses Geheimnis ist konzeptionell statisch, kann aber jeden Tag / jede Stunde geändert werden, um die Sicherheit zu verbessern. Dies ist die einzige vertrauliche Sache. - Lesen Sie die kryptische (aber für alle Benutzer statische!) Formular-ID mit JavaScript und verarbeiten Sie sie zusammen mit dem Benutzergeheimnis:
generateToken(7099879082361234103, 89070135420357234586534346)
- Senden Sie das Formular zusammen mit dem generierten Token an den Server.
- Da der Server das Benutzergeheimnis und die Formular-ID kennt, kann vor dem Senden und Vergleichen der beiden Ergebnisse dieselbe generateToken-Funktion wie beim Client ausgeführt werden. Nur wenn beide Werte gleich sind, wird die Aktion autorisiert.
Stimmt etwas mit diesem Ansatz nicht, obwohl er ohne JavaScript nicht funktioniert?
Nachtrag:
Antworten:
Hier gibt es viele Antworten und Probleme mit einigen von ihnen.
Dinge, die Sie NICHT tun sollten:
Wenn Sie das Sitzungstoken aus JavaScript lesen müssen, machen Sie etwas schrecklich Falsches. Auf Ihrem Sitzungskennungs-Cookie sollte IMMER HTTPOnly festgelegt sein, damit es für Skripte nicht verfügbar ist.
Durch diesen einen Schutz wird die Auswirkung von XSS erheblich verringert, da ein Angreifer kein angemeldetes Sitzungstoken für Benutzer mehr erhalten kann, das in jeder Hinsicht den Anmeldeinformationen in der Anwendung entspricht. Sie möchten nicht, dass ein Fehler dem Königreich Schlüssel gibt.
Die Sitzungskennung sollte nicht in den Inhalt der Seite geschrieben werden. Dies ist aus den gleichen Gründen, aus denen Sie HTTPOnly festlegen. Dies bedeutet, dass Ihr CSRF-Token nicht Ihre Sitzungs-ID sein kann. Sie müssen unterschiedliche Werte sein.
Dinge, die Sie tun sollten:
Befolgen Sie die Anweisungen von OWASP :
Wenn es sich um eine REST-Anwendung handelt, können Sie die doppelte Übermittlung von CSRF-Token verlangen . Wenn Sie dies tun, stellen Sie einfach sicher, dass Sie es für eine bestimmte vollständige Domain ( www.mydomain.com ) und nicht für eine übergeordnete Domain (example.com) definieren und dass Sie auch das Cookie-Attribut "samesite" verwenden, das an Bedeutung gewinnt Popularität.
Erstellen Sie einfach etwas kryptografisch Zufälliges, speichern Sie es in ASCII Hex- oder Base64-Codierung und fügen Sie es als Cookie und zu Ihren Formularen hinzu, wenn der Server die Seite zurückgibt. Stellen Sie auf der Serverseite sicher, dass der Cookie-Wert mit dem Formularwert übereinstimmt. Voila, Sie haben CSRF getötet, zusätzliche Eingabeaufforderungen für Ihre Benutzer vermieden und sich nicht für weitere Sicherheitslücken geöffnet.
HINWEIS: Wie in @krubo unten angegeben, weist die Double-Submission-Technik einige Schwachstellen auf (siehe Double-Submission) . Da diese Schwäche Folgendes erfordert:
Ich denke, die Schwäche fällt eher in die Kategorie eines "Cool Defcon Talk" als in ein "Realworld Security Risk". In jedem Fall schadet es nicht, ein paar zusätzliche Schritte zu unternehmen, um sich vollständig zu schützen, wenn Sie die doppelte Einreichung verwenden.
Neues Update 07/06/2020
Meine neue Lieblingsmethode für die doppelte Übermittlung besteht darin, wie zuvor eine kryptografische Zufallszeichenfolge im Hauptteil der Anforderung zu erstellen und zu übergeben. Anstatt dass das Cookie den gleichen exakten Wert hat, muss das Cookie der codierte Wert der Zeichenfolge sein, die von einem Zertifikat signiert wird. Dies ist auf der Serverseite immer noch genauso einfach zu überprüfen, für einen Angreifer jedoch VIEL schwerer nachzuahmen. Sie sollten weiterhin das gleiche Cookie-Attribut und andere Schutzmaßnahmen verwenden, die weiter oben in meinem Beitrag beschrieben wurden.
quelle
cross-origin HTTP request
Überprüfungen des Servers und der HTTP-Rückgabeheader von der API kann ein Großteil des automatisierten Schadens begrenzt werden, den ein Angreifer einem angemeldeten Benutzer zufügen kann.Verstehe ich das richtig:
Überprüfen Sie also, ob Benutzer per Cookie angemeldet sind, und wenden Sie CSRF erst dann an .
Ich bin nicht sicher, aber kann eine andere Site Dinge wie Basic Auth oder Header fälschen?
Soweit ich weiß, dreht sich bei CSRF alles um Cookies ? RESTful Auth tritt bei Cookies nicht auf.
quelle
Sie benötigen definitiv einen Status auf dem Server, um sich zu authentifizieren / zu autorisieren. Es muss jedoch nicht die http-Sitzung sein, sondern Sie können sie in einem verteilten Cache (wie memcached) oder einer Datenbank speichern.
Wenn Sie Cookies zur Authentifizierung verwenden, besteht die einfachste Lösung darin, den Cookie-Wert doppelt zu übermitteln. Bevor Sie das Formular senden, lesen Sie die Sitzungs-ID aus dem Cookie, speichern Sie sie in einem versteckten Feld und senden Sie sie dann ab. Vergewissern Sie sich auf der Serverseite, dass der Wert in der Anforderung mit der Sitzungs-ID übereinstimmt (die Sie vom Cookie erhalten haben). Böses Skript aus einer anderen Domäne kann die Sitzungs-ID nicht aus dem Cookie lesen, wodurch CSRF verhindert wird.Dieses Schema verwendet eine einzelne Kennung in der gesamten Sitzung.Wenn Sie mehr Schutz wünschen, generieren Sie eine eindeutige ID pro Sitzung und Formular.
Generieren Sie außerdem KEINE Token in JS. Jeder kann den Code kopieren und von einer anderen Domain ausführen, um Ihre Site anzugreifen.
quelle
Die statische Formular-ID bietet überhaupt keinen Schutz. Ein Angreifer kann es selbst holen. Denken Sie daran, dass der Angreifer nicht auf die Verwendung von JavaScript auf dem Client beschränkt ist. Er kann die statische Formular-ID serverseitig abrufen.
Ich bin mir nicht sicher, ob ich die vorgeschlagene Verteidigung vollständig verstehe. Woher kommt das
GET /usersecret/john_doe
? Ist das Teil der Seite JavaScript? Ist das die wörtlich vorgeschlagene URL? Wenn ja, gehe ich davon aus, dass diesusername
kein Geheimnis ist, was bedeutet, dass evil.ru Benutzergeheimnisse wiederherstellen kann, wenn ein Browser- oder Plugin-Fehler domänenübergreifende GET-Anforderungen zulässt. Warum nicht das Benutzergeheimnis bei der Authentifizierung in einem Cookie speichern, anstatt es von jedem abrufen zu lassen, der domänenübergreifende GETs ausführen kann?Ich habe "Robuste Abwehrmechanismen für standortübergreifende Fälschungen" sehr sorgfältig gelesen, bevor ich mein eigenes Authentifizierungssystem implementiert habe, das gegen CSRF resistent sein soll. Tatsächlich würde ich die Implementierung meines eigenen Authentifizierungssystems überhaupt überdenken.
quelle
GET /usersecret/john_doe
ist Teil des JavaScript. Der Benutzername selbst ist nicht das Geheimnis, sondern die ID, die mit dieser Anforderung von einem authentifizierten (!) Benutzer abgerufen wird. Danke für den Link.Es gibt einige Methoden im CSRF-Präventions-Spickzettel , die von einem erholsamen Dienst verwendet werden können. Die RESTful zustandslose CSRF-Minderung besteht darin, den Origin- oder HTTP-Referer zu verwenden, um sicherzustellen, dass die Anforderungen von einer Domäne stammen, der Sie vertrauen.
quelle
Ihr Benutzergeheimnis ist kein Geheimnis, wenn Sie es an den Client senden. Normalerweise verwenden wir solche Geheimnisse, um Hashes zu generieren, sie mit dem Formular zu senden und sie zum Vergleich zurück zu warten.
Wenn Sie RESTful sein möchten, muss die Anforderung alle Informationen zur Verarbeitung enthalten. So können Sie das machen:
Fügen Sie Ihrem REST-Client ein CSRF-Token-Cookie hinzu und senden Sie dasselbe Token in versteckter Eingabe mit Ihren Formularen. Wenn sich der Dienst und der Client unter verschiedenen Domänen befinden, müssen Sie die Anmeldeinformationen freigeben. Auf dem Dienst müssen Sie die 2 Token vergleichen, und wenn sie gleich sind, ist die Anfrage gültig ...
Sie können das csrf-Token-Cookie mit Ihrem REST-Service hinzufügen und dasselbe Token mit den Darstellungen Ihrer Ressourcen (versteckte Eingaben usw.) senden. Alles andere ist das gleiche wie das Ende der vorherigen Lösung. Diese Lösung steht am Rande von RESTfulness. (Es ist in Ordnung, bis der Client den Dienst nicht aufruft, um das Cookie zu ändern. Wenn das Cookie nur http ist, sollte der Client nichts davon wissen. Wenn dies nicht der Fall ist, sollte der Client es festlegen.) Sie können weitere Schritte ausführen Komplexe Lösung, wenn Sie jedem Formular unterschiedliche Token hinzufügen und den Cookies eine Ablaufzeit hinzufügen. Sie können die Ablaufzeit auch mit den Formularen zurücksenden, damit Sie den Grund kennen, warum eine Token-Validierung fehlschlägt.
Sie können ein Benutzergeheimnis (von Benutzer zu Benutzer unterschiedlich) im Ressourcenstatus Ihres Dienstes festlegen. Durch Erstellen von Darstellungen können Sie für jedes Formular ein Token (und eine Ablaufzeit) generieren. Sie können einen Hash aus dem tatsächlichen Token (und der Ablaufzeit, der Methode, der URL usw.) und dem Benutzergeheimnis generieren und diesen Hash auch mit dem Formular senden. Sie halten den "Benutzer geheim" natürlich geheim, also senden Sie das nie mit dem Formular. Wenn Ihr Dienst danach eine Anfrage erhält, können Sie den Hash aus den Anforderungsparametern und dem Benutzergeheimnis erneut generieren und vergleichen. Wenn die nicht übereinstimmen, ist die Anfrage ungültig ...
Keiner von ihnen schützt Sie, wenn Ihr REST-Client Javascript injizierbar ist. Sie müssen daher den gesamten Benutzerinhalt mit HTML-Entitäten vergleichen und alle entfernen oder TextNodes immer anstelle von innerHTML verwenden. Sie müssen sich auch vor SQL-Injection und HTTP-Header-Injection schützen. Verwenden Sie niemals einfaches FTP, um Ihre Site zu aktualisieren. Und so weiter ... Es gibt viele Möglichkeiten, bösen Code in Ihre Site einzufügen ...
Fast hätte ich vergessen zu erwähnen, dass GET-Anfragen immer vom Dienst und auch vom Kunden gelesen werden können. Für den Dienst ist dies offensichtlich. Wenn der Client eine URL im Browser festlegt, die eine Darstellung einer Ressource oder mehrerer Ressourcen ergeben muss, sollte er niemals eine POST / PUT / DELETE-Methode für eine Ressource aufrufen. Zum Beispiel
GET http://my.client.com/resource/delete -> DELETE http://my.api.com/resource
ist eine sehr, sehr schlechte Lösung. Dies ist jedoch eine sehr grundlegende Fähigkeit, wenn Sie CSRF behindern möchten.quelle