2010-02-05 8 views
41

Ich habe Probleme mit dem AntiForgeryToken in ASP.Net MVC. Wenn ich ein iisreset auf meinem Webserver mache und ein Benutzer mit seiner Sitzung fortfährt, werden sie auf eine Anmeldeseite weitergeleitet. Nicht schrecklich, aber dann explodiert der AntiForgen-Token und der einzige Weg, um wieder loszulegen, ist das Cookie im Browser wegzublasen.Wie löse ich eine AntiForgeryToken-Ausnahme, die nach einem iisreset in meiner ASP.Net MVC-App auftritt?

Mit der Beta-Version von Version 1 ging es falsch beim Lesen des Cookies zurück für mich, also habe ich es vor der Frage nach einem Validierungstoken schrubben, aber das wurde behoben, als es veröffentlicht wurde.

Für jetzt denke ich werde ich zurück zu meinem Code, der das Beta-Problem behoben, aber ich kann nicht helfen, aber denke, dass ich etwas vermisse. Gibt es eine einfachere Lösung, sollte ich einfach ihren Helfer fallen lassen und einen neuen von Grund auf neu erstellen? Ich habe das Gefühl, dass ein Großteil des Problems darin besteht, dass es so tief in die alte ASP.Net-Pipeline eingebunden ist und versucht, es zu etwas zu machen, für das es eigentlich nicht vorgesehen war.

Ich hatte einen Blick in den Quellcode für die ASP.Net MVC 2 RC und es sieht nicht aus wie der Code hat sich viel geändert, so, während ich es nicht versucht habe, glaube ich nicht, dass es irgendwelche Antworten gibt Dort.

Hier ist der relevante Teil des Stack-Trace der Ausnahme.

Edit: Ich habe gerade festgestellt, ich habe nicht erwähnt, dass dies nur versucht, das Token auf die GET-Anfrage einzufügen. Dies ist nicht die Validierung, die auftritt, wenn Sie einen POST-Kick-off ausführen.

System.Web.Mvc.HttpAntiForgeryException: A required anti-forgery token was not 
supplied or was invalid. 
---> System.Web.HttpException: Validation of viewstate MAC failed. If this 
application is hosted by a Web Farm or cluster, ensure that <machineKey> 
configuration specifies the same validationKey and validation algorithm. 
AutoGenerate cannot be used in a cluster. 
---> System.Web.UI.ViewStateException: Invalid viewstate. 
    Client IP: 127.0.0.1 
    Port: 4991 
    User-Agent: scrubbed 
    ViewState: scrubbed 
    Referer: blah 
    Path: /oursite/Account/Login 
---> System.Security.Cryptography.CryptographicException: Padding is invalid and 
cannot be removed. 
at System.Security.Cryptography.RijndaelManagedTransform.DecryptData(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount, Byte[]& outputBuffer, Int32 outputOffset, PaddingMode paddingMode, Boolean fLast) 
at System.Security.Cryptography.RijndaelManagedTransform.TransformFinalBlock(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount) 
at System.Security.Cryptography.CryptoStream.FlushFinalBlock() 
at System.Web.Configuration.MachineKeySection.EncryptOrDecryptData(Boolean fEncrypt, Byte[] buf, Byte[] modifier, Int32 start, Int32 length, IVType ivType, Boolean useValidationSymAlgo) 
at System.Web.UI.ObjectStateFormatter.Deserialize(String inputString) 
--- End of inner exception stack trace --- 
--- End of inner exception stack trace --- 
at System.Web.UI.ViewStateException.ThrowError(Exception inner, String persistedState, String errorPageMessage, Boolean macValidationError) 
at System.Web.UI.ViewStateException.ThrowMacValidationError(Exception inner, String persistedState) 
at System.Web.UI.ObjectStateFormatter.Deserialize(String inputString) 
at System.Web.UI.ObjectStateFormatter.System.Web.UI.IStateFormatter.Deserialize(String serializedState) 
at System.Web.Mvc.AntiForgeryDataSerializer.Deserialize(String serializedToken) 
--- End of inner exception stack trace --- 
at System.Web.Mvc.AntiForgeryDataSerializer.Deserialize(String serializedToken) 
at System.Web.Mvc.HtmlHelper.GetAntiForgeryTokenAndSetCookie(String salt, String domain, String path) 
at System.Web.Mvc.HtmlHelper.AntiForgeryToken(String salt, String domain, String path) 
+2

Siehe auch hinzufügen: http://stackoverflow.com/quest ionen/1360078/asp-net-mvc-validierung-von-viewstate-mac-failed – Shog9

Antwort

40

Wenn Ihre MachineKey auf Autogenerate gesetzt, dann Überprüfung Token, usw. wird keine Anwendung Neustart überleben - ASP.NET einen neuen Schlüssel erzeugen, wenn er startet, und dann nicht in der Lage sein, entschlüsseln Sie die Token korrekt.

Wenn Sie dies viel sehen, würde ich vorschlagen:

  1. eine statische MachineKey konfigurieren (Sie sollten diese auf der Anwendungsebene in der Lage zu tun), siehe "How to: Configure a MachineKey" für weitere Informationen
  2. Try nicht IIS Resets durchzuführen, wenn die Site

der beste Weg, dies ist, indem er eine lastausgeglichenen Anwendung zu tun verwendet wird, die w Andernfalls müssen Sie einen statischen MachineKey einstellen. Eine weitere Möglichkeit besteht darin, die Site downzuloaden, indem Sie eine Datei mit dem Namen app_offline.htm im Stammverzeichnis der Site platzieren. Dadurch wird die Site offline geschaltet und Ihre Nachricht wird angezeigt - zumindest erwarten die Benutzer, dass etwas schief läuft.

+0

Ahh, das könnte wohl das Problem sein. Ich werde es versuchen und wenn es funktioniert, werde ich das als die Antwort markieren. Es ist eine gute Idee, die IisResets nicht zu machen, aber ich versuche nur sicherzustellen, dass es in der realen Welt so zuverlässig wie möglich funktioniert. –

+3

Hier sind einige sehr gute Artikel zu diesem Thema http://adam.kahtava.com/journal/2009/11/23/how-to-fix-the-validation-of-viewstate-mac-failed-error- aspnet-mvc/ http: //adam.kahtava.com/journal/2009/11/25/Was-sind-Anti-Cross-Site-Anfrage-Fälschung-Tokens-und-was-sind-sie-gut-für/ – superlogical

+9

Ich habe richtige Maschinenschlüssel, aber manchmal habe ich HttpAntiForgeryException. :(Ich weiß nicht warum.:/ – dariol

4

Wenn ich ein iisreset auf meinem Webserver und ein Benutzer weiterhin mit ihren Sitzung sie zu einer Anmelde Seite zurückgesendet.

Es gibt keinen Grund, einen Iisreset die Benutzer auf die Login-Seite zu bringen. Wenn Sie Cookies verwenden, um Authentifizierungsinformationen zu verfolgen und eine zustandslose Anwendung zu verwenden, sollte der Benutzer auch nach einem Serverneustart authentifiziert bleiben (wenn eine Anfrage während des Zurücksetzens erfolgt, wird dies natürlich fehlschlagen).

+1

Das ist technisch wahr und etwas, was ich wirklich lösen sollte, aber das ist ein separates Problem. Die Tatsache, dass ich die Ausnahme bekomme, wenn ich versuche, das Token auf die Seite zu legen, ist das Problem. –

+1

@Darin - persistente Logins und der Anti-Fälschungsmechanismus sind abhängig von den ''-Werten, die in IISResets konsistent sind. Wenn sie auf AutoGenerate eingestellt sind, ändern sich die Schlüssel und der Cookie ist nicht mehr gültig. – Kev

+0

Ja, dies verursacht erhebliche Probleme in einer Shared Hosting-Umgebung, die stark ausgelastet ist. Ich habe jedoch eine Lösung für das "Keep me logged in" Problem gefunden, und das war, den 'machineKey' in meine' Web.config' zu setzen - das hat es gut gelöst. –

13

Für jetzt habe ich mit einer Lösung gegangen, die den Cookie scrubbt, wenn die Ausnahme ausgelöst wird. Wenn die Ausnahme erneut ausgelöst wird, lasse ich es einfach so geschehen, wie es war.

Ich werde dies nicht als "die" Antwort für jetzt in der Hoffnung, dass jemand eine bessere Antwort hat.

public static class MyAntiForgeryExtensions 
{ 
    // Methods 
    public static string MyAntiForgeryToken(this HtmlHelper helper) 
    { 
     return MyAntiForgeryToken(helper, null); 
    } 

    public static string MyAntiForgeryToken(this HtmlHelper helper, string salt) 
    { 
     string fragment; 
     string path = helper.ViewContext.HttpContext.Request.ApplicationPath; 
     try 
     { 
      fragment = helper.AntiForgeryToken(salt, null, path); 
     } 
     catch (HttpAntiForgeryException) 
     { 
      // okay, scrub the cookie and have another go. 
      string cookieName = GetAntiForgeryTokenName(path); 
      helper.ViewContext.HttpContext.Request.Cookies.Remove(cookieName); 
      fragment = helper.AntiForgeryToken(salt, null, path); 
     } 
     return fragment; 
    } 

    #region AntiForgeryData code that shouldn't be sealed 
    // Copied from AntiForgeryData since they aren't accessible. 
    internal static string GetAntiForgeryTokenName(string appPath) { 
     if (String.IsNullOrEmpty(appPath)) { 
      return "__RequestVerificationToken"; 
     } 
     else { 
      return "__RequestVerificationToken_" + Base64EncodeForCookieName(appPath); 
     } 
    } 
    private static string Base64EncodeForCookieName(string s) { 
     byte[] rawBytes = Encoding.UTF8.GetBytes(s); 
     string base64String = Convert.ToBase64String(rawBytes); 

     // replace base64-specific characters with characters that are safe for a cookie name 
     return base64String.Replace('+', '.').Replace('/', '-').Replace('=', '_'); 
    } 
    #endregion 
} 
+0

Ich habe das Gleiche gemacht. Ich denke, das ist ein großer Designfehler mit der 'AntiForgeryToken'-Methode, und wie deine Kommentare zeigen, ist es noch frustrierender, dass der MVC-Code intern/versiegelt ist, weil er uns daran hindert, ihn einfach zu reparieren! –

+0

In einem verwandten Hinweis ist es auch frustrierend, dass das ValidateAntiForgeryToken-Attribut versiegelt ist, da es auch einige Unzulänglichkeiten aufweist. Letztendlich habe ich die VAFT-Quelle gepackt, sie versiegelt und meine eigene Unterklasse erstellt, die auf einen ganzen Controller angewendet werden kann und JSON-Anfragen unterstützt. –

+0

Eine Sache, die ich für die MVC3-Unterstützung ändern würde, ist, dass Ihre statischen Helfererweiterungsmethoden MvcHtmlString zurückgeben sollten, da helper.AntiForgeryToken (string, string, string) diesen Typ anstelle einer einfachen Zeichenfolge zurückgibt. –

4

Eigentlich fand ich dies in meiner Anmelde Aktion zu arbeiten:

public ActionResult LogOn() 
    { 
     formsAuthentication.SignOut(); 

     Response.Cookies.Clear(); 

     Session[SessionKeys.USER_SESSION_KEY] = null; 
     Session.Clear(); 
     Session.Abandon(); 


     return View(); 
    } 

Der wichtige Teil war: Response.Cookies.Clear();

+0

Das funktioniert. Zaphs Hinweis zu den Maschinenschlüsseln funktioniert aber besser, weil es verhindert, dass Sie nach dem iisreset auf die Login-Seite zurückgeworfen werden. Es verhindert auch, dass der Cookie aufgrund eines –

+2

Ich habe auch einen statischen Maschinenschlüssel, aber hatte das gleiche Problem – Jeff

+1

Der Versuch, sich einzuloggen, wenn bereits eingeloggt ist, sollte nicht durch Einloggen des Benutzers bestraft werden.Im Falle, dass der Benutzer unwissentlich mehrere Fenster geöffnet hat und versehentlich auf a veraltete Anmeldeseite, riskiert der Benutzer den Verlust von Arbeit/Status in den anderen Fenstern. Eine bessere Lösung ist hier, sie an den Anmeldebildschirm weiterzuleiten, wie [Zia leitet sie an eine Anti-Panzer-Seite weiter] (http://stackoverflow.com/a/ 32624782/235908) –

10

Ich hatte dieses Problem und zu reparieren, was Sie tun müssen, ist ein expliziten Computerschlüssel in Ihrer Web-config hinzufügen ...

<machineKey validationKey="D82960E6B6E9B9029D4CAB2F597B5B4AF631E3C182670855D25FBDE1BFAFE19EFDE92ABBD1020FC1B2AE455D5B5F8D094325597CE1A7F8B15173407199C85A16" decryptionKey="577404C3A13F154908D7A5649EEC8D7C8A92C35A25A3EC078B426BB09D426A71" validation="SHA1" decryption="AES" /> 

sicherzustellen, sein in web.config platziert innerhalb ...

<system.web> 
+1

Vorgegebener Link funktioniert nicht Bitte verwenden Sie die folgende URL [http://www.allkeysgenerator.com/Random/ASP-Net-MachineKey-Generator.aspx] – Optimus

+1

Ich mag paranoid sein, aber ich würde nicht Verwenden Sie keine Internet-Website, um meine Schlüssel für mich zu generieren. Neuere Versionen von IIS können dies tun, und Sie können dies auch mit der .NET-Systemklasse 'RNGCryptoServiceProvider' tun. – Menahem

+0

Sie können paranoid sein, aber Sie haben auch recht. –

7

Sie AntiForgeryConfig.SuppressIdentityHeuristicChecks = true; in global.asax

protected void Application_Start() { 
    AntiForgeryConfig.SuppressIdentityHeuristicChecks = true; 
} 
+1

Was macht das genau? –

+0

@TimothyGroote von http://www.asp.net/mvc/overview/security/xsrfcsrf-prevention-in-aspnet-mvc-and-web-pages: "Ein Boolean, der diktiert, ob das Anti-XSRF-System deaktivieren sollte Wenn dieser Wert wahr ist, nimmt das System an, dass IIdentity.Name für die Verwendung als eindeutige benutzerspezifische ID geeignet ist, und versucht nicht, IClaimsIdentity oder ClClaimsIdentity in Sonderfällen wie im WIF/ACS/anspruchsbasierte Authentifizierung. Der Standardwert ist false. " Dies erfordert, dass IIdentity.Name ein ausreichend eindeutiger Bezeichner ist, um sicher zu sein. –

Verwandte Themen