__RequestVerificationToken is not always created

We have a page with several forms. Each of them has its own @Html.AntiForgeryToken() . Everything is fine on my local machine.

We deployed to Azure (PAAS), but the __RequestVerificationToken not created with every request. Once upon a time, and sometime I get the necessary anti-fake cookie, and rarely I get tokens that do not correspond to errors.

At this moment I do not know at all. I can’t understand if something is wrong in our code or in the Azure environment? There is no ajax in these forms.

We have added the <machineKey> section to our web.config. No caching. Sometimes this happens on new devices the first time.

+5
source share
2 answers

I believe that your problem is related to the presence of several forms with different tokens for faking on one page. When you request a page, you get two different tokens in the form of hidden fields, but only one token in cookies. The POST form contains inappropriate tokens that cause an error.

Try how AFT will work for you if the page contains only one form. If it works fine, my guess is correct.

This answer contains a possible solution for a page with multiple forms, but has some security flaws, as described here .

I'm not sure why everything works fine on your localhost. I created a simple application and tried the POST form with the correct cookie token, but the old form token from the previous session. To my surprise, such a POST succeeds. Perhaps asp.net has special handling for local requests in this case. I did not find any information about this.

If my answer still does not help, you can provide the following data for further analysis:

  • Original page request with returned HTTP headers and fake token form.
  • POST request form with sent HTTP headers.
+1
source

After spending a considerable amount of time with the investigation, using a combination of the Sentry and Azure web server logs, I found two main causes of the errors mentioned:

1) On mobile phones, when the browser is in the background, it may suddenly stop the OS to free up resources. When this happens, the page is usually stored on the telephone disk and reloaded from there when the browser reopens.

However, the problem is that by this point, the Anti-Forgery token, which is the session cookie, has already expired since it is essentially a new session. Thus, the page loads without the Anti-Forgery Cookie, using the HTML from the previous session. This throws the exception The required anti-forgery cookie is not present .

2) Apparently, the exception tokens do not match usually only related in relation. It seems that the reason is the user behavior when opening multiple tabs at the same time.

Anti-Forgery Cookie is assigned only when the user comes to a page with a form on it. This means that they may go to your homepage and not have an anti-fake cookie. Then they can open several tabs using the middle click. Multiple tabs are multiple concurrent requests, each of which does not contain an anti-fake cookie.

Since these requests do not have an anti-virus cookie, for each of them ASP.NET generates a separate pseudo-random token for its cookie and uses it in the form; however, only the result of the last header received will be saved. This means that all other pages will display invalid tokens on the page, as their anti-fake cookie has been canceled.

For the solution, I created a global filter, which should ensure that

  • The Anti-Forgery cookie is set on any page, even if the page does not have a form, and
  • The Anti-Forgery cookie is not associated with the session. This lifetime should be adjusted according to the user's login token, but it must be maintained between sessions if the mobile device reloads the page without a session.

Below is the FilterAttribute code that should be added inside FilterConfig.cs as a global filter. Please note that although I do not believe that this would create a security hole, I am by no means a security expert, so any input is welcome.

 [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] public class AntiForgeryFilter : FilterAttribute, IActionFilter { public void OnActionExecuting(ActionExecutingContext filterContext) { var cookie = filterContext.HttpContext.Request.Cookies.Get(AntiForgeryConfig.CookieName); var addCookie = true; if (string.IsNullOrEmpty(cookie?.Value)) { cookie = filterContext.HttpContext.Response.Cookies.Get(AntiForgeryConfig.CookieName); addCookie = false; } if (string.IsNullOrEmpty(cookie?.Value)) { AntiForgery.GetTokens(null, out string cookieToken, out string _); cookie = new HttpCookie(AntiForgeryConfig.CookieName, cookieToken) { HttpOnly = true, Secure = AntiForgeryConfig.RequireSsl }; } cookie.Expires = DateTime.UtcNow.AddYears(1); if(addCookie) filterContext.HttpContext.Response.Cookies.Add(cookie); } public void OnActionExecuted(ActionExecutedContext filterContext) { } } 
0
source

Source: https://habr.com/ru/post/1272522/


All Articles