I have been going through the error logs of a development project and found the following error (name changed to protect the guilty innocent)-
The provided anti-forgery token was meant for user "", but the current user is "admin".
This was not an especially difficult issue to reproduce-
- Open the application at the login page
- Open a second window or tab in the same browser on the same computer to the login page before logging in
- Login in the first window (or indeed second, the order doesn't matter)
- Attempt to login in the remaining login window
The stack trace is-
System.Web.Mvc.HttpAntiForgeryException (0x80004005): The provided anti-forgery token was meant for user "", but the current user is "admin". at System.Web.Helpers.AntiXsrf.TokenValidator.ValidateTokens(HttpContextBase httpContext, IIdentity identity, AntiForgeryToken sessionToken, AntiForgeryToken fieldToken) at System.Web.Helpers.AntiXsrf.AntiForgeryWorker.Validate(HttpContextBase httpContext) at System.Web.Helpers.AntiForgery.Validate() at System.Web.Mvc.ValidateAntiForgeryTokenAttribute.OnAuthorization(AuthorizationContext filterContext) at System.Web.Mvc.ControllerActionInvoker.InvokeAuthorizationFilters(ControllerContext controllerContext, IList`1 filters, ActionDescriptor actionDescriptor) at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass25.b__1e(AsyncCallback asyncCallback, Object asyncState)
The login method signature is-
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Login(LoginModel model, string returnUrl)
{
...
}
This is exactly the same as the signature for the method in a internet "ASP.NET MVC 4 Web Application" templated project, which indicates that Microsoft either felt the ValidateAntiForgeryToken was necessary/best practice, or simply added the attribute here because it was used everywhere else.
Obviously there is nothing I can do to handle the problem within this method as it isn't reached, the ValidateAntiForgeryToken is a pre-request filter and it is blocking the request before it reaches the controller.
I could check if the user is authenticated via Ajax before submitting the form and attempt to redirect to them if so, or simply remove the attribute.
The question is this - I understand that the token is design to prevent requests from another site (CSRF) when the user is already authenticated against your site so on that basis is it an issue to remove it from a form which by definition will be used by unauthenticated users?
Presumably the attribute in this instance is designed to mitigate malicious actors providing fake login forms for your application (although by the time the exception is thrown presumably the user has already entered his or her details which will have been recorded - but it might alert them something is wrong). Otherwise submitting incorrect credentials to the form from an external site will result in exactly the same result as on the site itself surely? I am not relying on client validation/sanitation to clean up potentially unsafe input.
Have other devs come across this issue (or do we have unusually creative users) and if so how have you resolved/mitigated it?
Update: This issue still exists in MVC5, entirely intentionally, now with the error message "The provided anti-forgery token was meant for a different claims-based user than the current user." when using default template and Identity providers. There is a relevant question and interesting answer from Microsoft Developer Evangelist and Troy's fellow PluralSight author Adam Tuliper at Anti forgery token on login page which recommends simply removing the token.