I have a site that receives a large amount of the following errors:
The provided anti-forgery token was meant for a different claims-based user than the current user.
The anti-forgery cookie token and form field token do not match.
I would like to prevent the site from throwing an error if the anti-forgery token is meant for no user but contains a user on the login page, for example:
The provided anti-forgery token was meant for user "", but the current user is "Garret".
I don't want this exception to apply to any other page other than the login page. So I don't want to add AntiForgeryConfig.SuppressIdentityHeuristicChecks = true;
to the entire site. I also want to keep the site as secure as possible since it contains HIPAA data. What can I do to keep it as secure as possible but still try to prevent this error on the login page because it is making it difficult for users to use?
The site is hosted on load balancing servers but I don't think this is the issue. I think the error is mostly caused by using the browser's back button, having the login page opened for a while before logging in, already being logged in or pressing login more than once. Also some users access it through an application that may not be loading the page and just trying to post the login information.
So please let me know what the best option is to prevent this error on the login page while still being as secure as possible?
Anti-forgery token validation is enabled by default in Razor Pages. You can disable validation either globally or on individual pages by using [IgnoreAntiforgeryToken] . You can prevent forms from creating anti-forgery tokens by using asp-antiforgery="false" in the form tag helper.
Try quick fixes The common “possible solutions” to anti-forgery token/cookie related issues are disabling output caching and enabling heuristic checks.
ASP.NET Core uses a hidden field to store the anti-forgery token and uses the ValidateAntiForgeryToken attribute to validate the token. As the token is sent to the browser in a hidden field, it is also stored in an HttpOnly cookie.
Anti-Forgery TokensOne token is sent as a cookie. The other is placed in a hidden form field. The tokens are generated randomly so that an adversary cannot guess the values. When the client submits the form, it must send both tokens back to the server.
What I ended up doing, and it seems to be working while still providing the same security, is to manually check the antiforgery token after checking if the user is logged in.
[HttpPost]
[AllowAnonymous]
//[ValidateAntiForgeryToken]
[OutputCache(NoStore = true, Duration = 0, VaryByParam = "None")]
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
// Skip the login process if the user is already logged in
if (User.Identity.IsAuthenticated)
{
return RedirectToAction("Index", "Home");
}
// Check the anti forgery token now
System.Web.Helpers.AntiForgery.Validate();
...
There is an answer for concurrent login attempts originated from certain user:
How can I fix anti-forgery token was meant for user "", but the current user is "xxxx " error
If AntiForgeryToken exception comes when the user has too long time to fill in login page, simply redirect to that page and show a message explaining his/her session (i.e. security token) had expired.
[HttpPost]
[ValidateAntiForgeryToken]
[HandleError(View="Login", ExceptionType = typeof(HttpAntiForgeryException))]
public ActionResult Login(LoginModel model)
{
// some login processing stuff
}
If the exception comes from user's clicking back button, provide JS function on client-side which prevent the back button action on login page only:
<body onload="window.history.forward()">...</body>
// or wrap it inside a function
<script type="text/javascript">
function noBackOnLogin() {
window.history.forward();
history.pushState(null, document.title, url); // if you want to include Mobile Safari, see https://stackoverflow.com/a/34337617/6378815
}
</script>
<body onload="noBackOnLogin();" onpageshow="if (event.persisted) noBackOnLogin();">...</body>
For another case that certain user has already logged in, redirect to the index or somewhat page indicating their user name (with User.Identity.Name
).
I hope this explanation useful.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With