36

If the answer is yes then how would ASP.NET MVC find out that which token was linked to which form and how to validate it?

I've seen it is creating two separate tokens for each form.

neebz
  • 11,465
  • 7
  • 47
  • 64

2 Answers2

35

There is nothing specific that you need to do in this case. ASP.NET MVC will simply reuse the same value for all forms so it doesn't need to know which form sent the request in order to validate it. Simply put an Html.AntiForgeryToken() in each form and decorate each controller action you are posting to with the [ValidateAntiForgeryToken] attribute and you should be OK.

Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • one last bit, what would happen if I put an Antiforgerytoken on the top of the body tag and use that for all my `$.post()` requests ? Will it be able validate it? I am still confused with multiple tokens on the page, how does the framework knows which token is for which form or what if the token is placed outside the form (but inside the body) and is being reused for every ajax request? – neebz May 09 '11 at 06:45
  • @nEEbz, yes putting the token inside the body and reusing it for AJAX requests will work. But you can also use one of the hidden fields inside the form for the AJAX request. Why adding yet another token? Or even better: simply use `$('#someformid').serialize()` and send this as the `data` parameter to the AJAX request. – Darin Dimitrov May 09 '11 at 06:47
  • 1
    yea when I have a form, I am using the AjaxForm plugin (which converts the form to an ajax request) but sometimes I don't have a form; A plain link which triggers a post request. For that I was thinking I'll add a antiforgerytoken in the master page and use it for all things ajax. thanks – neebz May 09 '11 at 06:51
  • It is a bit confusing, mostly because all the articles I was able to find, such as [this one](http://blog.stevensanderson.com/2008/09/01/prevent-cross-site-request-forgery-csrf-using-aspnet-mvcs-antiforgerytoken-helper/) are stating something like "At the same time, Html.AntiForgeryToken() will give the visitor a cookie called __RequestVerificationToken, with the same value as the random hidden value shown above.", but I guess that statement is simply false, isn't it? – Michal Hosala Sep 30 '15 at 20:56
  • As two forms on the same page have different anti forgery token, while the __RequestVerificationToken cookie is only one based on your answer. – Michal Hosala Sep 30 '15 at 20:57
  • 24
    The answer as posted is not correct "ASP.NET MVC will simply reuse the same value for all forms so it doesn't need to know which form sent the request in order to validate it. " I have multiple forms on a page and have called Html.AntiForgeryToken() for each form and each one creates a unique value -- and I am having problems with "The provided anti-forgery token was meant for a different claims-based user than the current user. " – DJA Nov 14 '15 at 13:36
  • 13
    i confirm what DJA reported, i'm in the same situation: i have three forms all of which have different requestverificationtoken and also different from the value inside the cookie,, my ajax post request is being rejected with a 401 unauthorized response code... any deeper explanations please? – Souhaieb Besbes Dec 30 '15 at 16:15
  • @SouhaiebBesbes I've got a page with only two forms on it, both using `@Html.AntiForgeryToken()` to generate the verification token, and can happily submit both forms - which version of MVC are you using (I'm on 5.2.3.0)? – Zhaph - Ben Duguid Jan 12 '16 at 14:58
  • @DarinDimitrov, would you please help me in [this question](http://stackoverflow.com/questions/39077877/how-to-setup-jquery-ajax-calls-to-inject-an-antiforgerytoken-globally-in-thair-r) too? – Ramin Bateni Aug 22 '16 at 14:01
  • 1
    I have the same issue as @DJA and @SouhaiebBesbes. Two forms on the same page, each with a `Html.AntiForgeryToken()`, generate two different tokens and then one (or both?) doesn't mach the single cookie. Did anyone find a solution? – savehansson Oct 05 '16 at 13:57
  • 1
    Me again. There is a solution, albeit with some security concerns, here: http://stackoverflow.com/a/22479124/593779 – savehansson Oct 05 '16 at 14:08
  • the cookie isn't actually supposed to be the same as the token. They are passed into a validator separately and each is decrypted and then they are compared. – John Lord Jun 30 '21 at 17:59
14

There is a great article here I pointed out some important sections.

In a nutshell, If a token can be deserialized from the request’s cookie collection, it’ll reuse that token instead of generating a new one. If a token doesn’t exist in the cookie collection, it’ll instantiate a new instance of “AntiForgeryToken” and randomly generate a new 16 byte array to represent the token.

public AntiForgeryToken GetCookieToken(HttpContextBase httpContext)
{
    HttpCookie cookie = httpContext.Request.Cookies[this._config.CookieName];

    if (cookie == null || string.IsNullOrEmpty(cookie.Value))
        return (AntiForgeryToken) null;

    return this._serializer.Deserialize(cookie.Value);
}

After generating the first token and saving it to the cookie collection, all subsequent calls to the helper method “Html.AntiForgeryToken()” will follow the same steps and reuse the existing token from the cookie collection instead of generating a new value.

Since it is a session cookie, this means the anti-forgery token’s value is generated only once during a browser session and is reused for all subsequent calls.

So why are the hidden field values different from one another if they are reusing the same token?

So while the encrypted values may look different, the decrypted values are the same.

byte[] one = MachineKey45CryptoSystem.Instance.Unprotect("iAdQj5D0qrMuTggD8WpnOZPlVOfHg_qmPIEjnULAYd1h56cV2cL51rcaY8_UgxQbav5_6KTAtyE52ir1X6GmaS9ZPgw1");
byte[] two  = MachineKey45CryptoSystem.Instance.Unprotect("Shvi8Bxe6-a8zfCfDGnxkaC-IETsbjkR9iIylwn-2VRWQ-GtQkdowdFw1biU7dN3j-xPJZHYQPe-hNfWspYjy_ZcCCY1");
byte[] three = MachineKey45CryptoSystem.Instance.Unprotect("ZhaVFngUMLo88jmTIx___BTWlYFyKh1GalwEeffRl0-o3Gu7_m98k6aQjO7IysZIdXxVx6TqL6QIfX19Uwq3Ia6dghA1");

Comparing all three byte arrays reveals they are identical.

erhan355
  • 806
  • 11
  • 23
  • this should be the accepted answer. It's not only technically accurate, but it has links and examples of WHY it is accurate. – John Lord Jun 30 '21 at 17:59