aspnetcore: Apparently Random Error: "Antiforgery token validation failed. The antiforgery cookie token and request token do not match."
Background
I have a relatively new ASP.NET Core 2 site. It’s running on just one server (Windows Server 2012 R2, IIS 8.5), and I only restart the site once every few days when I upload an update. About once a day, a user’s request fails due to rejection by the anti-forgery system. These are POST requests, and there’s nothing particularly special about them. I’m including the anti-forgery value in the POST request, and 99% of the time, POST requests work. But when they don’t, the stdout log says, “Antiforgery token validation failed. The antiforgery cookie token and request token do not match.” I’ve already posted this question on Stack Overflow and the ASP.NET Core forums, and I haven’t gotten any useful answers.
Errors
I’ve included the relevant portions of the stdout log below.
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
Request starting HTTP/1.1 POST [domain redacted] application/x-www-form-urlencoded 234
info: Microsoft.AspNetCore.Mvc.ViewFeatures.Internal.ValidateAntiforgeryTokenAuthorizationFilter[1]
Antiforgery token validation failed. The antiforgery cookie token and request token do not match.
Microsoft.AspNetCore.Antiforgery.AntiforgeryValidationException: The antiforgery cookie token and request token do not match.
at Microsoft.AspNetCore.Antiforgery.Internal.DefaultAntiforgery.ValidateTokens(HttpContext httpContext, AntiforgeryTokenSet antiforgeryTokenSet)
at Microsoft.AspNetCore.Antiforgery.Internal.DefaultAntiforgery.<ValidateRequestAsync>d__9.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNetCore.Mvc.ViewFeatures.Internal.ValidateAntiforgeryTokenAuthorizationFilter.<OnAuthorizationAsync>d__3.MoveNext()
info: Microsoft.AspNetCore.Mvc.RazorPages.Internal.PageActionInvoker[3]
Authorization failed for the request at filter 'Microsoft.AspNetCore.Mvc.ViewFeatures.Internal.AutoValidateAntiforgeryTokenAuthorizationFilter'.
info: Microsoft.AspNetCore.Mvc.StatusCodeResult[1]
Executing HttpStatusCodeResult, setting HTTP status code 400
info: Microsoft.AspNetCore.Mvc.RazorPages.Internal.PageActionInvoker[2]
Executed action /Index in 2.6224ms
warn: Microsoft.AspNetCore.Antiforgery.Internal.DefaultAntiforgery[1]
Antiforgery validation failed with message 'The antiforgery cookie token and request token do not match.'.
For requests that result in the above stdout output, IAntiforgery.IsRequestValidAsync agrees by returning false. Notice the error message “The antiforgery cookie token and request token do not match.” Here’s a reduced example of a failed POST request and the associated cookie.
POST: __RequestVerificationToken= CfDJ8F9Fs4CqDFpLttT96eZw9WHjWfHO8Yawn35k4Yq3gDK5n1TDJDDiY5o86VQs1_qOVIYBydCizBU4knb7Jmq1-heGhwnMu2KmhUIiAd0xI7Sudv3GX-J0OI6wRfiPL4L1KRs2Pml8dbsDfwemewBqi18
Cookie: .AspNetCore.Antiforgery.ClRyCRmWApY=CfDJ8F9Fs4CqDFpLttT96eZw9WFtJht41WcNrmgshi2pFGwcxhr0_0hvINQc7Yl9Cbjhv-TiSNXeEctyKborLI49AcjHfWIgOmmKkbjOe7QMn8Z0WZtkQy5JcaBHKEGTu1p-La8JL8pZZqZy02Hrswpkh3I
I’ve also captured this data a few times after the request has failed with a 400 error (using some error handling middleware):
AntiforgeryTokenSet tokens = antiforgery.GetTokens(context);
tokens.CookieToken: null
tokens.FormFieldName: "__RequestVerificationToken"
tokens.HeaderName: "RequestVerificationToken"
tokens.RequestToken: "CfDJ8F9Fs4CqDFpLttT96eZw9WH33jSw5mM8h7RpEd3vGISQTRkx1rfwm-L2lfkvXKMBc-riESmoTo_fnIjeBbRmOo5KuJHr09f8B75sQ9g_djIVeeaGwMw5KE6W1O2-7Vi03fCnwlTv8l-BWGst76Ln-ZQ"
So here are the three strings:
POST String: "CfDJ8F9Fs4CqDFpLttT96eZw9WHjWfHO8Yawn35k4Yq3gDK5n1TDJDDiY5o86VQs1_qOVIYBydCizBU4knb7Jmq1-heGhwnMu2KmhUIiAd0xI7Sudv3GX-J0OI6wRfiPL4L1KRs2Pml8dbsDfwemewBqi18"
Cookie String: "CfDJ8F9Fs4CqDFpLttT96eZw9WFtJht41WcNrmgshi2pFGwcxhr0_0hvINQc7Yl9Cbjhv-TiSNXeEctyKborLI49AcjHfWIgOmmKkbjOe7QMn8Z0WZtkQy5JcaBHKEGTu1p-La8JL8pZZqZy02Hrswpkh3I"
antiforgery.GetTokens(context).RequestToken: "CfDJ8F9Fs4CqDFpLttT96eZw9WH33jSw5mM8h7RpEd3vGISQTRkx1rfwm-L2lfkvXKMBc-riESmoTo_fnIjeBbRmOo5KuJHr09f8B75sQ9g_djIVeeaGwMw5KE6W1O2-7Vi03fCnwlTv8l-BWGst76Ln-ZQ"
The POST string and cookie string don’t match, but in my experience, even with requests ASP.NET Core considers legitimate, they never do. But strangely, the POST string and tokens.RequestToken don’t match either. I would think they should match, although I captured tokens.RequestTooken later in the request lifecycle, so maybe that has something to do with it.
ASP.NET Core 2 on GitHub
I decided to look at the source code of ASP.NET Core 2. I found this file, especially line 145:
That line gets the message “The antiforgery cookie token and request token do not match.” from this file at line 134:
https://github.com/aspnet/Antiforgery/blob/dev/src/Microsoft.AspNetCore.Antiforgery/Resources.resx
So I think that’s where the message is originating, but I’m still left wondering why this is happening.
Question
Would someone please help me figure out why these anti-forgery tokens aren’t validating? Is it possible the user’s Web browser is mangling the cookie or POST data? Does anyone have experience in this area or any suggestions? Thank you.
About this issue
- Original URL
- State: closed
- Created 6 years ago
- Reactions: 3
- Comments: 51 (18 by maintainers)
Commits related to this issue
- Negotiate + SignalR Service Support for the Java client (#2882) — committed to dotnet/aspnetcore by mikaelm12 6 years ago
We’ve been experiencing this problem for several years in a production application on ASP.NET MVC 5 (though similar anti-forgery mechanism to ASP.NET Core). Our application has a few components that are mini-single-page-applications. So, there’s a lot of requests via JavaScript that we do that include anti-forgery protection. We’ve been able to prevent anti-forgery errors by introducing a couple of changes:
localStoragesessionevents or using the Broadcast Channel API) and show a message on the “stale” tab. A lot of sites do this similar pattern (e.g. GitHub, AWS Console, etc). This reduced a large majority of our problems.Although this fixed most of our problems, we still have had consistent anti-forgery problems from some of our users. We have a heartbeat-like request that sends useful information for aggregating/reporting later on in the user interface. This heartbeat-like request would continuously fail for certain users meaning that their data was lost and couldn’t be reported on. Thankfully, the anti-forgery error was transparent to them but it meant a discrepancy in data for reporting.
In a recent investigation back into this problem, I found some interesting revelation in our logs:
Here’s what this is caused by:
/applesand/bananas).__RequestVerificationTokencookie is cleared because it’s only alive for as long as the browser’s session..ASPXAUTHcookie is not cleared because it has a default expiration of 1 year./applesand/bananasare launched concurrently in our app. This could also be accomplished just by doing something like middle-clicking on a tab more than once, but the pattern seems to fit since this causes the referrer to be empty. Both of those pages render a form with the anti-forgery token (e.g.@Html.AntiForgeryToken()).__RequestVerificationTokencookie and send it as part of the response because the request does not have a__RequestVerificationToken. When the form’s token is generated during the request, it’s for the unique cookie token per-request.I have some ideas to work around this, though I haven’t fully thought them through:
Does anyone else have any ideas on how we could solve this problem? @wessleym I’m not entirely sure if any of this can help solve your problem but I hope it may be able to provide some insight.
If it’s worth something, iv’e been facing this issue since ASP.NET MVC 5. As it is described it happens 1 on 1000 times apparently random. No matter how hard I try, I still cannot reproduce this behaviour
We’re seeing the same strange behavior. Once in a while, a user will get a the exception: “Antiforgery token validation failed. The antiforgery cookie token and request token do not match.” when logging in to the website.
About the following question earlier:
We support only HTTPS. For the given situation in bullet 2, a different error is thrown, so according to me, that’s an entirely different issue: “The provided antiforgery token was meant for a different claims-based user than the current user.” I think this is by design, and we accept that.
It seems to happen after a while after the user session and login have timed out, and the user tries to login again, although I’m unable to consistently reproduce the issue (the login/session timeout serverside doesn’t seem to be the only cause).
Regarding our solution We used the examples on https://docs.microsoft.com/en-us/aspnet/core/security/anti-request-forgery?view=aspnetcore-2.1 We use the header option in the AddAntiforgery call:
services.AddAntiforgery(options => options.HeaderName = "X-CSRF-TOKEN");We globally registered the AutoValidateAntiForgeryToken filter:
services.AddMvc(options => options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute()));We also include an AntiForgeryToken in a cookie, according to the example in the webpage above:"
context.Response.Cookies.Append("CSRF-TOKEN", tokens.RequestToken, new Microsoft.AspNetCore.Http.CookieOptions { HttpOnly = false, Secure = true });This token is read by clientside javascript and used in AJAX requests by setting the X-CSRF-TOKEN header.
Hoping to at least find a root cause for when this happens (so something reproducable), since then, we can figure out how to prevent this from happening.
@mkArtakMSFT, I appreciate your time and your stance. But as my original post stated, this problem is not easily reproducible. It seems to happen randomly. I wish I could supply projects, but not only are the projects owned by my paying clients, but they also reliably work in my testing. It’s only in production, maybe every 1,000 requests, that they fail. So while this GitHub issue may be closed, the real-world issue continues. @javiercn, while I don’t think this my problem since I’m not generally seeing requests so close together and since my page load times are pretty low, would you be able to supply documentation about this? “Another situation where this might occur is when a user opens multiple tabs simultaneously (specially if the page takes time to load) where the requests go on simultaneously and the responses are sent concurrently (in which case the two cookies get set at the same time and one of that will cause one of them to fail) but eventually the browser will settle for the last cookie in the response. (Note that this is an unavoidable race condition that happens when there’s no cookie and the user opens multiple tabs simultaneously).”
Pfff. I’m investigating a maybe similar issue with this. At first it seemed random, later it seems it only happens when having Chrome DevTools open together with “Enable JavaScript source maps” enabled, INCLUDING a 404 generated by a ‘custom’ middleware.
I’ll try to explain it a clearly a possible what our situation is, as I THINK it is, but I’m not sure this situation is ‘fixable’ in ASP.NET Core, or that it has to be fixed by excluding .map files, or not sending cookie updates etc.
AutoValidateAntiforgeryTokenAttribute:UseStatusCodePagesWithReExecute, nothing really special inside thisErrorController:But I guess because it is all processed through a real Controller it will alter the Cookie and messing up the expected and send Token.
We open a site with a form, which includes a .min.js file, with a source mapping (
//# sourceMappingURL=jsfile.min.js.map) in itChrome WILL AUTOMATICALLY download this source mapping file, you WONT see it in the Network tab… But it WILL alter your cookie of the current page!! Which will ‘invalidate’ the expected one.
I really hope this is the problem you all might be having so that we have found the underlying vague issue and can move on 😃
I used Charles proxy, breakpoints and cURL to reproduce this issue. I downloaded a HTTP2 enabled cURL build for Windows: https://winampplugins.co.uk/curl/ (No idea why it is hosted on a winamp related site)
Path to reproduce:
set-cookie: .AspNetCore.Antiforgery.PLlJ9KQhgiA=TAKETHISPARTVery small update. The screenshot on step 5 now ‘works’ (the right page/view is shown) because I added
[IgnoreAntiforgeryToken]to theInvalidRequestWithStatusCodeaction… Ofcourse, when trying to access anything with a bad token it indeed does not work 😃Hi,
I’ve been looking at the issue you mentioned. There are a few things a user could do to cause this. So here are a few questions: