Why does @Html.AntiForgeryToken() generate different tokens in same response?
Asked Answered
S

6

7

A single Razor view contains several forms, each with its own call to @Html.AntiForgeryToken()

<form id="f1">
    @Html.AntiForgeryToken()
</form>

<form id="f2">
    @Html.AntiForgeryToken()
</form>

As I understand it, both of these anti forgery tokens should be the same.

<form id="f1">
    <input name="__RequestVerificationToken" type="hidden" value="duVT4VtiYybun-61lnSY1ol__qBwawnELooyqT5OSrCJrvcHvDs_Nr9GLxNxwvBaI4hUcKZVkm6mDEmH2UqNorHD1FnJbKJQLWe8Su_dhy_nnGGl5GhqqC3yRGzcxbBM0" />
</form>

<form id="f2">
    <input name="__RequestVerificationToken" type="hidden" value="ZMISz3IWHU_HCKP4FppDQ5lvzoYhlQGhN1cmzKBPz4OgDzyqSUK3Q1dqvw1uHsb4eNyd9U3AbFcnW8tR7g1QS8Dyhp0tFc-ee1sfDAOqbLCcgd3PDnLCbXx09pnPREaq0" />
</form>

Why are the values different?

Surely they should be the same, because they are sent in the same Response from the server?
The documentation says nothing about calling it once only.

Sumy answered 18/3, 2014 at 11:44 Comment(1)
Keep in mind that vtortola's approach creates a security flaw, as explained in my answer below. The tokens HAVE to be different.Leoine
H
2

The Anti-Forgery token is not compared directly - the server has to unprotect it first and compare the protected data inside. Having different protected tokens doesn't necessarily mean they contain differing data.

What the System.Web.Helpers.AntiXsrf.TokenValidator compares is the SecurityToken inside the decrypted AntiForgeryToken instances. These instances, however, also contain an AdditionalData field, a UserName field and a ClaimUid field.

Also, the SecurityToken inside the AntiForgeryToken is directly copied from the (current if it is valid, else the freshly generated) AntiForgery cookie inside AntiForgeryWorker.

Given that all that data is serialized, encrypted then encoded, you may have variances in the protected token due to differences between the AdditionalData between tokens or it is likely due to a pseudorandom nonce used in the encryption process (which it likely uses, since I can test 2 completely different tokens as valid against the same cookie).

Hydrotherapy answered 5/11, 2017 at 17:2 Comment(0)
L
12

I am afraid that won't work.

The antiforgery token also travels in the response cookie, so yours will contain just the last token, and therefore the first form will always fail.

You can try to do something like this:

@{
    ViewBag.Title = "Index";
    var token = Html.AntiForgeryToken();
}

<form id="f1">
    @token 
</form>

<form id="f2">
    @token 
</form>

I have tried it, and the same token is used in both forms.

Librate answered 18/3, 2014 at 12:16 Comment(18)
Do you know why the values are different?Sumy
Because every call generates a different token, that is, there is no more to dig about that. The MSDN says "Generates a hidden form field (anti-forgery token) that is validated when the form is submitted.", so that "Generates" states that a new one will be generated each time :)Librate
Why would anyone want two different anti-forgery tokens?Sumy
Why are indexers of arrays Int32, why would anyone want to set an array to a negative length? It should be UInt32 or UInt16 :) I don't say it is right or wrong, I only say how it works according to the spec.Librate
What specification are you referring to?Sumy
msdn.microsoft.com/en-us/library/…Librate
That doesn't specify the behaviour when used more than once (which I need to do). But surely it should generate a valid anti-forgery token each time?Sumy
The meaning of "Generate" is "create" or "produce". This implicit in the name of the method that it will create a new whatever. Otherwise the method would be named "GetAntiForgeryToken" or something similar.Librate
I'm just interested in an answer to my question - why are the values different?Sumy
I told you already, because that method "generates" a token each time you call it.Librate
and WHY does it do that?Sumy
because if it returned the same token every time you called it, then you would get the same token on different pages, and somebody could just copy it to do CSRF attack. if you need to use the token in two different places (because your page has two forms) then this is the correct answer.Crabb
Well it could generate the same token every Response, instead of every call. What's wrong with that?Sumy
nothing is wrong with that. The developer that made this helper decided to generate it once per call. Thats the API. It was the developer's decision (likely a lot of them weighed in). If you'd like the behavior you describe, implement it yourself - that's the beauty of programming!Crabb
Your approach creates a security vulnerability, as stated in my answer provided below. You should not use the same token for every form present in the page.Leoine
I think you are confused, we are not talking about the same token in all SITE (collection of PAGE ), but the same token in two forms in the same PAGE (single html resource).Librate
no, i'm talking about the same html resource with various form entities.Leoine
Now this thing works ie if you have two forms on same page and two tokens, both forms can be submitted successfully.Incorporeal
L
4

The values HAVE to be different. Not because of implementation inner workings or API voodoo but because each form represents an independent request to the server.

If the forms had the same token, once an attacker knew the token value for one form he would be able to trick the server into accepting the data sent by the other forms, although they were not submitted by the user, defeating the protection provided by the AntiCSRF Token.

The objective of the token is to provide a random id parameter, making it very hard for the attacker to fool the application into thinking that it was the logged in user that filled the form.

For those that are not acquainted with CSRF attacks, please take a look here.

Leoine answered 17/12, 2014 at 18:27 Comment(9)
So how does the attacker get the token of one of the forms?Librate
MitM would one of the ways to see that. DNS poisoning would be another one. Attacks that defeat "same-origin policy" (even android browser suffers from this) would also enable an attacker to read the page contents, therefore allowing him to read the token via javascript.Leoine
That applies for one form with one antiforgery token as well. With a MitM attack possible, your token will bet visible from the HTML response and the Set-Cookie HTTP header. Even if the MitM only allowed to intercept from client to server, the attacker still can change the data you are sending without having previous knowledge of the tokens. Also, if an attacker gets to read the page you have in the browser, it does not matter if you have one token in one form or two tokens in two forms.Librate
The token used once cannot be used again, or i would not have to know it before-hand. Reusing same-session past tokens would be enough to defeat it. So, once the user uses it, the attacker cannot do it again. Also, there are different MitM types, Passive and Active MitM. Sometimes he may intercept traffic and change it, sometimes he may only watch it pass.Leoine
If security tokens are not invalidated upon use, all it would take for me to create my own admin user would be to replay the original request, only changing the chosen credential.Leoine
I have to check, ASP.NET MVC may reject the second token post. The idea behind XSRF protection, is that the attacker cannot guess the token in the form, if that were possible, this counter measure will be totally useless. So if a user is already vulnerable to a MitM attack, XSRF is rendered useless.Librate
See owasp.org/index.php/…, specially when it says: "In general, developers need only generate this token once for the current session."Librate
Well, just after that paragraph, OWASP says "To further enhance the security of this proposed design, consider randomizing the CSRF token parameter name and or value for each request." Quoting the answer you linked, generating one token per-page will break client usage, as only one valid token at once will break the app with the described back button issue. Having a token per-form will allow them to use the other form (as long as they are submitted only once). Also, i disagree with the per-session approach, as it gives me time to bruteforce it (I've seen people using 64bit long SessionIDs...)Leoine
What's the point of generating a new token for each request in a session? Did you validated whether the tokens cannot be valid for subsequent request? If yes, then do you think asp.net is itself managing all this stuff in-memory?Carlie
H
2

The Anti-Forgery token is not compared directly - the server has to unprotect it first and compare the protected data inside. Having different protected tokens doesn't necessarily mean they contain differing data.

What the System.Web.Helpers.AntiXsrf.TokenValidator compares is the SecurityToken inside the decrypted AntiForgeryToken instances. These instances, however, also contain an AdditionalData field, a UserName field and a ClaimUid field.

Also, the SecurityToken inside the AntiForgeryToken is directly copied from the (current if it is valid, else the freshly generated) AntiForgery cookie inside AntiForgeryWorker.

Given that all that data is serialized, encrypted then encoded, you may have variances in the protected token due to differences between the AdditionalData between tokens or it is likely due to a pseudorandom nonce used in the encryption process (which it likely uses, since I can test 2 completely different tokens as valid against the same cookie).

Hydrotherapy answered 5/11, 2017 at 17:2 Comment(0)
C
0

Surely they should be the same, because they are sent in the same Response?

The Response has nothing to do with it. @Html.AntiForgeryToken() is a static method of HtmlHelper which generates a unique token that is added to the html and the response cookie. Your calling the method multiple times so your generating multiple tokens.

If it did not generate a unique token each time it would hardly be secure.

Chatav answered 29/11, 2014 at 5:19 Comment(3)
Sorry, I meant reponse not request. Question amended, but still stands - why generate two different tokens in the HTML, when there is only one token in the cookie?Sumy
@buffjape, I don't understand why you think calling a method that returns a unique value would, or could, ever return duplicate values - its just not possible. Its no different than creating a method that has var a = Guid.NewGuid; var b = Guid.NewGuid; The values of a and b will be different. By your logic they should be the equal because they are in the same method. Perhaps you should study the source code to get a better understandingChatav
As I understand it, the purpose of @Html.AntiForgeryToken() is to put a specific anti-forgery token on the page (so that it matches the cookie). I already know it doesn't do that. What I'm looking for is a rational explanation...Sumy
A
0

@Html.AntiForgeryToken() basically generate encrypted value based on the cookie and form data. So if you declare and use this @Html.AntiForgeryToken() for each than it will generate two different _RequestValidationToken. Better declare one global @token variable with @Html.AntiForgeryToken() method and it will create a single token for each request.

Andorra answered 30/11, 2014 at 15:53 Comment(0)
E
-1

These are not equal antiforgerytoken commands.

The MVC is generate uniqe for all uniqe commands.

So you shouldnt wait same generated ID. As I know :)

Thank you buffjape, for your comment

Eyde answered 18/3, 2014 at 11:50 Comment(2)
Putting them in the same form made no difference. Two calls to @Html.AntiForgeryToken() always generate different values.Sumy
I think that browser bugs will cause such this problem some times.Morlee

© 2022 - 2024 — McMap. All rights reserved.