How to solve the AntiForgeryToken exception that occurs after iisreset in my ASP.Net MVC application?

I am having problems with AntiForgeryToken in ASP.Net MVC. If I do iisreset on my web server and the user continues their session, they will bounce to the login page. Not scary, but then the AntiForgery token will explode, and the only way to return is to demolish cookies in the browser.

With beta version 1, it messed up when reading the cookie for me, so I used it to clean up before asking for a validation token, but that was fixed when it was released.

At the moment, I think I will return to my code that fixed the beta problem, but I can’t help, but I think I missed something. Is there a simpler solution, hell, should I just drop the helper and create a new one from scratch? I get the feeling that the big problem is that it is so deeply attached to the old ASP.Net pipeline and trying to clone it, doing something that it was not going to do.

I looked at the source code for ASP.Net MVC 2 RC, and it doesn't look like the code has changed much, so while I haven't tried it, I don't think there are answers to it.

Here is the relevant portion of the exception stack trace.

Edit: I just realized that I didn’t mention that this is just an attempt to insert a marker in a GET request. This is not a check that occurs when you run POST.

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) 
+41
asp.net-mvc csrf
Feb 05 '10 at 10:45
source share
6 answers

If your MachineKey is set to AutoGenerate, then your validation tokens, etc. cannot survive the restart of the application - ASP.NET will generate a new key at startup, and then will not be able to correctly decrypt the tokens.

If you see this a lot, I would suggest:

  • Configure static MachineKey (you must do this at the application level), see "How to Configure MachineKey" for more information.
  • Do not attempt to reset IIS when using the site 1

1 The best way to do this is to have a downloaded application that will require the installation of a static MachineKey. Another option is to delete the site by placing a file named app_offline.htm in the root directory that will shut down the site and display your message. At least users will expect something to go wrong.

+39
Feb 05 '10 at 13:39
source share

At the moment, I went with a solution that clears the cookie if an exception is thrown. If the exception is thrown again, I will just let it happen as it was.

I will not mark this as an “answer” at the moment in the hope that someone will have a better answer.

 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 } 
+12
Feb 05 '10 at 11:27
source share

I had this problem, and to fix what you need to do is add an explicit machine key to your web configuration ...

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

ensure its placement in web.config inside ...

 <system.web> 
+9
Jun 21 '13 at 9:59
source share

You can add AntiForgeryConfig.SuppressIdentityHeuristicChecks = true; in global.asax

 protected void Application_Start() { AntiForgeryConfig.SuppressIdentityHeuristicChecks = true; } 
+7
Dec 06 '13 at 10:29
source share

If I do iisreset on my web server and the user continues the session they get a bounce from the login page.

There is no reason for iisreset to bring the user to the login page. If you use cookies to track authentication information and use the stateless application, the user must authenticate even after the server reboots (of course, if the request is executed during reset, it will not work).

+4
Feb 05 '10 at 10:50
source share

Actually, I found this to work in my login action:

  public ActionResult LogOn() { formsAuthentication.SignOut(); Response.Cookies.Clear(); Session[SessionKeys.USER_SESSION_KEY] = null; Session.Clear(); Session.Abandon(); return View(); } 

The important part: Response.Cookies.Clear ();

+4
Mar 27 '10 at 18:26
source share



All Articles