Why does @Html.AntiForgeryToken() generate differe

2019-01-23 20:32发布

问题:

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.

回答1:

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).



回答2:

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.



回答3:

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.



回答4:

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



回答5:

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.



回答6:

@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.