2012-03-29 9 views
15

Wir haben eine ASP.NET MVC 2 (.NET 4) -Anwendung unter Windows Azure (neueste 2.x OS-Version) mit zwei Webrolleninstanzen.Warum tritt HttpAntiForgeryException zufällig sogar mit einem statischen Maschinenschlüssel auf?

Wir verwenden das Anti-Fälschungs-Token, das von MVC für alle POST-Anfragen bereitgestellt wird, und wir haben in web.config einen statischen Maschinenschlüssel festgelegt, sodass alles auf mehreren Maschinen und Neustarts funktioniert. 99,9% der Fälle funktioniert es perfekt.

Hin und wieder jedoch protokollieren wir eine HttpAntiForgeryException mit der Meldung "Ein erforderliches Anti-Fälschungs-Token wurde nicht bereitgestellt oder war ungültig."

Ich weiß, das Problem könnte sein, dass Cookies im Browser nicht erlaubt sind, aber wir haben überprüft, dass Cookies aktiviert sind und korrekt gesendet werden.

Der Fehler tritt bei einer Vielzahl von Browsern auf und verursacht offensichtlich Probleme für die Benutzer, da sie den Vorgang wiederholen müssen oder einige Daten verlieren können. Es genügt zu sagen, dass wir das Problem nicht lokal reproduzieren konnten, sondern nur unter Windows Azure.

Warum passiert das? Wie können wir es vermeiden?

+0

Ich habe mit den Sicherheitsleuten (auf der MVC-Team) überprüft und Darin hat wahrscheinlich Recht - der Benutzername wahrscheinlich geändert. – RickAndMSFT

Antwort

0

Es gibt ein paar Optionen für das, was Sie ausprobieren könnten. Sie könnten versuchen, in die Maschine zu wechseln und sich das Ereignisprotokoll anzusehen, um zu sehen, ob Sie mehr Informationen darüber erhalten können, wo dies geschieht. Wenn das nicht hilft, können Sie DebugDiag oder ein anderes Tool verwenden, um einen Speicherauszug des Prozesses zu erfassen (DebugDiag lässt Sie einen zum Zeitpunkt dieser bestimmten Ausnahme erfassen). Und dann sieh dir das an, um zu sehen, was vor sich geht.

Wenn Sie es nicht von dort herausfinden können, können Sie immer einen Supportfall mit Microsoft erstellen, der Ihnen bei der Untersuchung hilft.

7

Das Anti-Fälschungs-Token enthält den Benutzernamen des aktuell verbundenen Benutzers, wenn es ausgegeben wird. Und wenn seine Gültigkeit überprüft wird, wird der aktuell verbundene Benutzer mit demjenigen verglichen, der verwendet wurde, als das Token ausgegeben wurde. Wenn Sie zum Beispiel ein Formular haben, in dem der Benutzer noch nicht authentifiziert ist und Sie ein Anti-Fälschungs-Token ausgeben, wird kein Benutzername darin gespeichert. Wenn Sie beim Übermitteln des Formulars den Benutzer authentifizieren, ist das Token nicht mehr gültig. Gleiches gilt für das Abmelden.

Hier ist, wie die Validate-Methode wie folgt aussieht:

public void Validate(HttpContextBase context, string salt) 
{ 
    string antiForgeryTokenName = AntiForgeryData.GetAntiForgeryTokenName(null); 
    string str2 = AntiForgeryData.GetAntiForgeryTokenName(context.Request.ApplicationPath); 
    HttpCookie cookie = context.Request.Cookies[str2]; 
    if ((cookie == null) || string.IsNullOrEmpty(cookie.Value)) 
    { 
     throw CreateValidationException(); 
    } 
    AntiForgeryData data = this.Serializer.Deserialize(cookie.Value); 
    string str3 = context.Request.Form[antiForgeryTokenName]; 
    if (string.IsNullOrEmpty(str3)) 
    { 
     throw CreateValidationException(); 
    } 
    AntiForgeryData data2 = this.Serializer.Deserialize(str3); 
    if (!string.Equals(data.Value, data2.Value, StringComparison.Ordinal)) 
    { 
     throw CreateValidationException(); 
    } 
    string username = AntiForgeryData.GetUsername(context.User); 
    if (!string.Equals(data2.Username, username, StringComparison.OrdinalIgnoreCase)) 
    { 
     throw CreateValidationException(); 
    } 
    if (!string.Equals(salt ?? string.Empty, data2.Salt, StringComparison.Ordinal)) 
    { 
     throw CreateValidationException(); 
    } 
} 

Eine Möglichkeit, dies zu debuggen ist ASP.NET MVC von seinem Quellcode neu zu kompilieren und melden Sie sich genau in dem der, wenn Fälle, die Sie eingeben, wenn die Ausnahme ist geworfen.

+0

Die Sicherheitsleute im ASP.NET MVC-Team stimmen zu, der Nutzername hat sich wahrscheinlich geändert. Jetzt, wo MVC Open Source ist, könnten Sie einen diagnotischen Zweig erstellen. Eine kleine Anmerkung, das AF-Token enthält NICHT den Benutzernamen - der Code zeigt, dass der Benutzername vom Form-Token kommt, nicht vom Cookie-Token. – RickAndMSFT

+0

Das Problem besteht darin, dass wir die ASP.NET-Authentifizierung nicht verwenden und den Benutzer/die Identität nie festlegen. Kann sich der Nutzername selbst ändern (vorausgesetzt, die App wird als Netzwerkdienst auf Azure ausgeführt)? –

+0

Haben Sie versucht, ASP.NET MVC aus dem Quellcode neu zu kompilieren und die Rückverfolgung zu überprüfen, in welchem ​​Fall die Überprüfung fehlschlägt? –

15

Ich bin auch kürzlich dazu gekommen und habe zwei Ursachen gefunden.

1. Browser wieder letzte Sitzung auf offen für Seite, die

zwischengespeichert wird, wenn Sie eine Seite haben, die cachable ist, die einen Beitrag zu Ihrem Server (dh Fälschungs auf wird) führt und der Benutzer hat ihre browser set zum wiederherstellen der letzten sitzung beim start (diese option existiert in chrome) wird die seite aus dem cache gerendert. Das Cookie für die Anfrageüberprüfung ist jedoch nicht vorhanden, da es sich um ein Browsersitzungs-Cookie handelt und beim Schließen des Browsers verworfen wird. Da der Cookie weg ist, erhalten Sie die Fälschungsausnahme. Lösung: Geben Sie Antwortheader zurück, sodass die Seite nicht zwischengespeichert wird (z. B. Cache-Control: privat, nicht gespeichert).

2.Race-Bedingung, wenn mehr als eine Registerkarte beim Start zu Ihrer Website geöffnet wird

Browser haben die Möglichkeit, beim Start eine Reihe von Registerkarten zu öffnen. Wenn mehr als eine dieser Websites Ihre Website mit einem Cookie zur Anfragebestätigung erreicht, können Sie eine Race-Bedingung treffen, bei der das Cookie für die Anfragebestätigung überschrieben wird. Dies liegt daran, dass mehr als eine Anfrage Ihren Server von einem Benutzer abruft, für den der Cookie für die Anfragebestätigung nicht festgelegt wurde. Die erste Anfrage wird bearbeitet und setzt das Anfrage-Verifizierungs-Cookie. Als nächstes wird die zweite Anfrage bearbeitet, aber sie hat das Cookie nicht gesendet (war noch nicht zur Anfragezeit gesetzt), so dass der Server eine neue generiert. Die neue überschreibt die erste, und jetzt erhält diese Seite eine Antiforderungsanforderung, wenn sie als nächstes einen Beitrag ausführt. Das MVC-Framework verarbeitet dieses Szenario nicht. Dieser Fehler wurde dem MVC-Team von Microsoft gemeldet.

+0

Ich sehe auch Bedingung 2. Es passiert nur dem ersten Benutzer. Sobald die Seite für den ersten Benutzer geladen ist, passiert das nicht mehr. – GnomeCubed

1

Ich habe ein paar MVC3 Web-Apps, die das auch regelmäßig bekommen. Die Mehrheit von ihnen ist, weil der Kunde eine POST-Stelle nicht sendet. Und die meisten davon sind IE8 wegen eines Bugs mit Ajax-Anfragen vor einem regulären Formular Post. Es gibt einen Hotfix für IE, die die Symptome zu behandeln scheint, die Art beweist der, dass es sich um eine Client-Fehler in diesen Fällen ist

http://support.microsoft.com/?kbid=831167

Es gibt einige Diskussionen über das Thema rund um das Web, nichts zu nützlich, wenn ich bin auf jeden Fall nicht zu verwirren mit Keep-alive-Timeouts, die eine vorgeschlagene „Lösung“ an einigen Stellen ...

https://www.google.com/search?q=ie8+empty+post+body

ich habe es nie in der Lage zu reproduzieren, mit einer Vielzahl von Versuchen, Reset-Verbindungen zwischen POSTS, so fürchte ich habe keine echte Lösung für den Fall der IE leere POST Körper. Die Art und Weise, wie wir es ein bisschen gemildert haben, besteht darin, sicherzustellen, dass wir niemals die POST-Methode verwenden, wenn wir nur Daten über Ajax abrufen.

Wenn Sie die vollständige Anfrage protokollieren, überprüfen Sie, ob der POST-Textkörper leer ist. Ist dies der Fall, handelt es sich wahrscheinlich um einen älteren IE. Und ich meine nicht Content-Length: 0, es wird normalerweise eine Content-Length haben, die in den Headern korrekt zu sein scheint, aber es wird buchstäblich nichts nach den Headern in der Anfrage geben.

Das Problem als Ganzes ist mir immer noch ein Rätsel, weil wir immer noch die Ausnahme bekommen, wo es einen vollständigen POST Körper gibt. Unsere Benutzernamen ändern sich nie und unsere Schlüssel sind ebenfalls statisch. Ich habe nicht versucht, der Quelle Debugging hinzuzufügen, wenn ich dazu komme, werde ich meine Ergebnisse melden.

0

Ich habe ähnliche Probleme mit meinem selbstgebrannten Anti-Fälschungs-Code, der konzeptionell dem MVC-Mechanismus sehr ähnlich ist, festgestellt. Meistens scheint das Problem aufzutreten, weil moderne Browser bereit sind, zwischengespeicherte Kopien von Seiten anzuzeigen, die als nicht zwischengespeichert angegeben sind.

Ich habe alle Kombinationen von Seite no-Cache-Direktiven versucht, aber manchmal bekomme ich immer noch zwischengespeicherte Seiten angezeigt.

Ich habe gefunden, dass eine bessere Lösung ist, das onbeforeunload-Ereignis für die Seite zu haken und explizit den Wert des ausgeblendeten Eingabefeldes zu löschen, das den Token-Wert im DOM enthält.

Wenn eine zwischengespeicherte Kopie einer Seite geladen wird, scheint es den gelöschten Eingabefeldwert zu enthalten. Ich teste dann für diese im Dokument-Ready-Funktion und die Seite neu laden, falls erforderlich:

window.location.reload(true); 

scheint sehr effektiv zu arbeiten, und ich vermute, es könnte für die MVC zu Fälschungs Code.

Verwandte Themen