MVC3 AntiForgeryToken bricht beim Ajax-Login ab

8

Der AntiForgeryToken -Mechanismus von ASP.NET MVC basiert auf dem aktuellen HttpContext.User . Es verwendet diesen Wert, um das Token zu erstellen, wenn Sie Html.AntiForgeryToken() aufrufen. Grundsätzlich ist es in Ordnung (siehe eine Erklärung im letzten Absatz hier ), aber ein Problem entsteht Wenn Sie sich über einen Ajax-Anruf anmelden .

Wenn ein Benutzer sich anmeldet, werden die Anmeldeinformationen in einem JSON-Objekt in Ajax gesendet (der AntiForgeryToken -Hide-Feldwert wird auch innerhalb des JSON gesendet), der Server authentifiziert den Benutzer, wendet FormsAuthentication.SetAuthCookie ( ) und gibt ein Json-Ergebnis zurück, das einige benutzerspezifische Daten enthält. Auf diese Weise kann ich eine vollständige Aktualisierung der Seite bei der Anmeldung vermeiden.

Das Problem ist, dass jede nachfolgende Ajax-Anfrage an den Server nun auf ValidateAntiForgeryTokenAttribute fehlschlägt, weil jetzt ein Anti-Fälschungs-Token erwartet wird, das nicht mit dem Anti-Fälschungs-Cookie kompatibel ist.

Wie kann ich ein gültiges Anti-Fälschungs-Token erhalten, das in das versteckte Feld des Clients eingefügt wird, damit jede JSON-Anfrage nach der Anmeldung erfolgreich ist?

Ich habe versucht, manuell ein neues verstecktes Feld-Token zu erhalten (mit AntiForgery.GetHtml() für die Aktion, die Token-Zeichenkette selbst extrahieren, sie in Json an den Client zurücksenden und sie manuell in JavaScript in das versteckte Feld für Fälschungssicherheit einfügen) aber es funktioniert nicht - ein nachfolgender Ajax-Aufruf schlägt auf dem ValidateAntiForgeryTokenAttribute auf dem Server fehl. Tatsächlich erzeugt jeder Aufruf von AntiForgery.GetHtml() (was im Wesentlichen das ist, was Html.AntiForgeryToken() helfer tut) ein anderes Token, das die vorherige ungültig macht.

Ich habe auch versucht, HttpContext.User = new GenericPrincipal(new GenericIdentity(email), null); als detaillierte hier zu setzen, aber das tut es nicht arbeite nicht.

Hinweis: Diese Lösung funktioniert aufgrund meiner spezifischen Situation nicht für mich: Ein Ajax Login , der die Benutzeridentität auf dem Server ändert und daher jedes Token, das vor der Anmeldung generiert wurde, ungültig ist; diese Lösung gilt auch nicht, weil es anspricht ein anderes Problem.

    
Ofer Zelig 17.10.2011, 11:39
quelle

2 Antworten

6

Sie müssen alle vorhandenen Formular-Token, die Sie beim Anmelden haben, löschen und wiederherstellen. Das bedeutet, dass Ihr Login-Code entweder die aktuelle Seite aktualisieren muss (der Ajax-Teil wird eh gekillt werden), Ihre eigene Token-Implementierung oder Sie müssen Ihr Token aktualisieren. Sie können eine Teilansicht anfordern, das Token extrahieren und das Formular aktualisieren. Sie könnten tatsächlich eine erholsame URL haben, die einem authentifizierten Benutzer nur ein Token zurückgibt. Man könnte argumentieren, dass dies ein Sicherheitsproblem ist, aber ich glaube nicht, weil es einfach ein einfacherer Weg ist, ein Token zu erhalten, als irgendeine Ansicht zu fordern - teilweise oder anderweitig.

Sie sollten in der Lage sein, die Token-Instanzen einfach zu ersetzen:

%Vor%

BEARBEITEN Nachdem ich ein paar Mal mehr gelesen habe, frage ich

Warum sollten Sie ein Token auf dem Formular haben, wenn der Benutzer nicht angemeldet ist? Sie erlauben, dass das gleiche Formular "bedient" wird, wenn Sie nicht eingeloggt und eingeloggt sind? Die meisten Websites im Netz werden auch in diesem Fall für eine Anmeldung weitergeleitet. Verstehe ich das richtig? Wenn dies der Fall ist, sollten Sie in Erwägung ziehen, das Token hier zu überspringen oder einen zweiten Tokentyp für nicht authentifizierte Benutzer zu verwenden. Sie glauben, ich sage, ein nicht authentifizierter Benutzer kann bereits etwas in der Anwendung einreichen - auch wenn ich das richtig verstanden habe - ohne authentifiziert zu werden.

    
Adam Tuliper - MSFT 18.10.2011, 18:42
quelle
3

Ok, was ich getan habe, war die Antwort von hier: jQuery Ajax Aufrufe und die Html.AntiForgeryToken () mit einer partiellen. Ich benutze Knockout, aber für diejenigen von euch, die nicht damit vertraut sind, sollten Sie trotzdem in der Lage sein, ziemlich leicht zu folgen.

Zuerst mein html:

%Vor%

Der Hauptunterschied besteht darin, dass ich anstelle von @ Html.AntiForgeryToken () ein AntiForgeryToken partial habe, das @ Html.AntiForgeryToken () enthält.

Um wirklich klarzustellen, habe ich jetzt eine AntiForgeryToken.cshtml Datei mit nur:

%Vor%

Jetzt, wenn Sie sich an- / abmelden, müssen Sie das Token aktualisieren, damit das javascript / jquery wie folgt aussieht:

%Vor%

Die Hauptsache, auf die hier zu achten ist, ist, dass das $ .get nach dem $ .post zum SignIn / Out passieren muss. Dieser Code könnte ein bisschen aufgeräumt werden, aber das ist das wichtigste Take-away. Wenn Sie das nicht tun, kann die $ .get-Datei (da sie asynchron ist) wahrscheinlich zurückkommen, bevor Sie tatsächlich angemeldet sind.

Das sollte es tun. Ich bin nicht zu anderen Zeiten gekommen, als der Token aktualisiert wird, aber es würde nur einen anderen Anruf erfordern, um den Teil zu aktualisieren.

    
rball 22.08.2012 17:35
quelle