MVC AntiForgeryToken reused previous generated tokens - asp.net-mvc

currently i'm working on ASP .NET MVC 4 application. We are using the provided [ValidateAntiForgeryToken] and the corresponding #Html.AntiForgeryToken() to generate the hidden field in our forms which are submitted using POST.
So far the mechanism seems to be working properly because if I don't provided the token as input hidden field to the target Action annotated with [ValidateAntiForgeryToken] an error is raised as expected.
However i found really strange that if i captured several generated token using Firebug or Chrome inspector, copy them into notepad and then go to a different page which also uses the AntiForgeryToken and basically replace the hidden field with any of the previous token generated, an error is not raised. I was expecting to always have a 1:1 relation (Page Hidden Field - ValidationAtServer], since if someone is able to obtain that value, will be able to forge any request to any form in the application which need the AntiForgeryToken
I was under the impression that once a token was generated it should not be possible to reuse the same token over an over, I see this a security flaw in the Framework itself.
If someone can provide more insight will be greatly appreciate it.

AntiForgeryToken is session base, so that each user has the same token but another user will have a different token. This descussion may be usefull for you: AntiForgeryToken changes per request

It's normal behaviour, because it's supposed that antiforgery token isn't compromised. If an atacker was able to compromise token, that means that atacker already has opportunity to compromise any other tokes, that would be generated. E.g. man in middle attacks.
So basically there is no need to gereate Antiforgery token per each request, and it will allow you to use already generated one for Ajax requests on current page.

Related

What is the use of #Html.AntiForgeryToken()?

Why we need to use #Html.AntiForgeryToken()?
I searched but I didn't get satisfactory answer.
This is a security feature to help protect your application against cross-site request forgery.
Example:
Let's assume you have a register functionality in your web app. You have an AccountController (example.com/account/register) where you expect people to submit their info. Normally before someone posts the registration information needs to visit the actual (example.com/account/register) than submit the form.
Let say I am a bad guy and I want to flood your server with junk info all I need to do is just keep posting directly to (example.com/account/register) without visiting your site. So in order to stop me you implement AntiForgeryToken so you can make it sure I visited the page before I submitted the registration information.
Another example is http://www.binaryintellect.net/articles/20e546b4-3ae9-416b-878e-5b12434fe7a6.aspx.
This is to prevent Cross-site request forgery in your MVC application. This is part of the OWASP Top 10 and it is vital in terms of web security. Using the #Html.AntiforgeryToken() method will generate a token per every request so then no one can forge a form post.
What is the use of #Html.AntiForgeryToken()?
Live - Scenario :
Suppose, you are logged into your bank account and are going to transfer some money to your friend. A hacker knows that you are logged in and also knows the URL of the money transfer submission. Suddenly, you get an email and check it. You see an image and by mistake, you click on that. Then, after a minute or so, you get another message that some amount has been deducted from your account. Actually, that image had been sent by the hacker and behind that image a URL has been submitted on your click.
So that we use AntiForgeryToken() in application prevent from hackers.
Antiforgery() is for stopping robotic fill up of any forms. Which will stop adding data without getting into the form
AntiForgeryToken is a security token generated by the .Net Core web application, which is used to validate a post request to guard against Cross-Site Request.
AntiforgeryToken used for validating the post request. So if we access an MVC or RazorPages view which contains the form element with an attribute 'method="post"' then the view gets rendered with an automatic generated AntiforgertyToken value, which gets injected into the form as hidden input field.

Umbraco 7 custom cookies

I am running an MVC site along side Umbraco. The MVC site handles its own authentication completely separate to Umbraco, and ASP.NET Forms authentication for that matter. It sets a cookie and uses that internally to keep track of things.
Everything works fine for the most part, but if I am logged into my MVC site with the aforementioned cookie set, I try to login to the Umbraco admin section using the correct Umbraco credentials, it authenticates me and redirects me to the admin section but the WebAPI calls start to fail. The first is a call to: /umbraco/backoffice/UmbracoApi/UpdateCheck/GetCheck which returns a 417 Missing token null HTTP error response.
If I delete my custom cookie and refresh the page everything works fine.
I don't understand how my cookie can interfere with Umbraco's. It's not using ASP.NET Forms authentication or anything.
This error occurs because your request is not sending up the required angular CSRF headers + cookie. I'm not sure why this would be the case but it does seems strange if it is a fault of your custom cookie. Perhaps you can tell us some more information about your issue: Cookie name/value, steps to reproduce, specific version of Umbraco, hosting environment, etc....
Some info as to what is going on, the code that returns this error is here:
https://github.com/umbraco/Umbraco-CMS/blob/dev-v7/src/Umbraco.Web/WebApi/Filters/AngularAntiForgeryHelper.cs#L94
This is where the CSRF cookies are set:
https://github.com/umbraco/Umbraco-CMS/blob/dev-v7/src/Umbraco.Web/WebApi/Filters/SetAngularAntiForgeryTokensAttribute.cs
and this attribute is applied to two actions, one for login and one when we retrieve the current user data:
https://github.com/umbraco/Umbraco-CMS/blob/dev-v7/src/Umbraco.Web/Editors/AuthenticationController.cs#L103
https://github.com/umbraco/Umbraco-CMS/blob/dev-v7/src/Umbraco.Web/Editors/AuthenticationController.cs#L84
This is where the header is set in the JS:
https://github.com/umbraco/Umbraco-CMS/blob/5b9a98ad6ae9e63322c26f7b162204e34f7fcb54/src/Umbraco.Web.UI.Client/src/init.js#L11
Depending on your hosting environment/setup there has been strange reports of some firewalls stripping/changing data, for example:
http://our.umbraco.org/forum/umbraco-7/using-umbraco-7/47340-Umbraco-7-plus-ISA-Server-2006
Hopefully given the info above you might be able to pinpoint where the problem starts.
My initial thought is that you by accident used a key value for your cookie that is reserved by Umbraco, which could result in the wrong cookie being read, causing issues. The solution to this would be to simply rename your cookie.
If this is not the case I have another theory:
HTTP requests will always include all cookies which path/domain matches the domain of the resource you are requesting. They are sorted by path length primarily, and secondarily by creation time. If Umbraco backend for some reason finds the cookie used for authentication by its index number (wouldn't even be surprised) in the list, rather than key value, your custom cookie would cause the index to shift, thus making Umbraco look at the wrong cookie
So, if renaming the cookie didn't do anything, a fun thing to try could be to set path of the cookie to the shortest possible path, which would make your browser put the cookie further down the list, so the index won't shift.
It's just a theory though, so I'm interested in hearing how it goes :)

AJAX CSRF attacks and .Net MVC

This post describes a tokening system for all JSON HttpGet and HttpPost AJAX calls:
In short, you use the AntiForgeryToken attribute to create a token on the page, and then manually validate that that value is sent back to the controller via the AJAX call.
http://www.asp.net/web-api/overview/security/preventing-cross-site-request-forgery-(csrf)-attacks
After hours of internet sleuthing, there are always references to this possibility, but no one actually implements it. Instead the commonly repeated techniques are 1) using only HttpPost AJAX requests (which breaks REST), 2) wrapping all json responses in an anonymous object, which results in significantly inelegant code in .net MVC4, 3) using an unparsable cruf, which breaks common libraries such as backbone.js
So why aren't we all using the tokening system linked above? What am I missing?
If you're concerned about CSRF, and your concerned about REST and doing REST correctly, then you shouldn't be doing anything in a GET that would be affected by a CSRF, since the entire purpose of AntiForgeryTokens is to deal with changing data (ie, you can't use an AntiForgeryToken without first getting the page anyways that contains the token).
So, saying using POST "breaks REST" seems to be misunderstanding what you're using the token for in the first place. It's true that a GET can expose sensitive information, but you have to have some way to get the token first if you want to use it with GET.
The real problem with Ajax and AntiForgeryToken with json and Ajax is that the "built-in" validation only works with form values, not json. So you have to do the validation yourself, and that article you linked to gives a good explanation of how to do that.

RequestVerificationToken does not match

I have a problem with the anti CRSF MVC mechanism. The cookie and the form input returned does not match. I'm getting an error every single time, only in one specific page. In the rest of the application it works well.
The server is returning HTTP 500 Internal Server Error and I can see on the log this exception:
[System.Web.Mvc.HttpAntiForgeryException]: {"A required anti-forgery
token was not supplied or was invalid."}
This is the hidden input that the server is generating is:
<input name="__RequestVerificationToken" type="hidden" value="QK8P7rjyZE6Vm5seY7Fr704YCOoFGdTIMzl1W7R0ZFpXSMjGKLG2T05DfFSYTxvtQCEx7DDT69DGsDB2+ZXFHY8oAjiKz0gw8BhDFywgmfIpoXnGpj7fONNzIIfvbrDrE9WJsMu6Io/0bDLM5WfKs0zktiNjyOWpfYrmnfINYmjW8NLOZFoz74xTcgTptAld">
And this is the Cookie returned:
Set-Cookie:__RequestVerificationToken_L2VGbG93=skmTAVI8HCbfxDS+xhioIMIISL3UOBI7qJM1JbHjTtAqKl4W70pDUcTKMm0p3R3mrHDziE8vXw0C0OO4HArzWO1/e6py+v/cFdbe9maFgjl4jMiZ9Wc4YIhC6+IUXkk6yqJDJ8dCIr8qtGaYcD9IX+m7/SlVhu521KQSWJYRcaY=; path=/; HttpOnly
When I examine what the server is sending, the cookie is exactly the same, but the payload has different encoding I think:
__RequestVerificationToken:QK8P7rjyZE6Vm5seY7Fr704YCOoFGdTIMzl1W7R0ZFpXSMjGKLG2T05DfFSYTxvtQCEx7DDT69DGsDB2%2BZXFHY8oAjiKz0gw8BhDFywgmfIpoXnGpj7fONNzIIfvbrDrE9WJsMu6Io%2F0bDLM5WfKs0zktiNjyOWpfYrmnfINYmjW8NLOZFoz74xTcgTptAld
The differences are in two characters that appear encoded:
/ -> %2F
+ -> %2B
Those are the only differences I can find between the hidden input field, and the post payload.
What could be the problem that is causing that ValidateAntiForgeryToken fails in verify the token?
Regards.
I've had and resolved several issues with ValidateAntiForgeryToken lately, so I'll share my findings with you.
Salt: Since you mention this only happens on a single page, my best guess is that you are using different salt values in your calls to Html.AntiForgeryToken(salt) and ValidateAntiForgeryToken(salt) calls.
AJAX: as another answer has said, using AJAX may require extra work to ensure the token is included in the POST. Here is my favorite simple, automatic solution to add the token to all AJAX POST requests.
In your question though, you state that you have verified that the token is sending. Have you verified that you're only sending the token once? I found out that an AJAX call of mine was sending the token twice, which combined the values, and caused it to fail.
Machine Key and Cookies: this issue is ugly, easy to spot (causes exceptions), but not very intuitive. The validation cookies and tokens are encoded and decoded using a unique "machine key". This means that if you have a server farm, or change your server, your cookie will no longer be valid. Closing your browser fixes the issue (because the cookie is a session cookie). However, some people leave their browser windows open in the background for a long time!
The solution is to set a "machine key" in your config file. This will tell MVC to use the same key on all servers, ensuring that the cookie will be decryptable everywhere.
Encoding Bugs: using a testing utility called jMeter, we attempted to load-test our pages, only to find out that it had a bug that caused our token to have 2 extra " around the value.
The solution is to lower your trust in your tools! Test in a browser, and if that works, create a test that extracts the token and cookie values, and set a breakpoint to verify the results.
If none of these things work for you, then I'd recommend taking a look at the MVC source code for ValidateAntiForgeryTokenAttribute, specifically the OnAuthorization method. It will help you see the different steps where validation could fail. You might even inspect your error's Exception.StackTrace to determine which part is failing.
As a side note, I really dislike the implementation of ValidateAntiForgeryToken in MVC, because:
There are about 5 verification steps that can fail, but there is only one generic error message.
The class is sealed, so it cannot be extended with additional functionality.
The encryption method is weird - it initializes a Page and creates an artificial ViewState to encrypt the tokens and cookies. Seems overkill.
So, I grabbed the source code, and created my own specialized subclass, which also turned out to be very helpful in debugging its issues, because I could set breakpoints on the validation methods, and it was really easy to determine which validation step was failing.
If this is being sent as an Ajax request, then the current setup of the framework isn't build to do this naturally.
Luckly Phil Haak wrote a nice blog post on dealing with CSRF and Ajax -> Preventing CSRF With Ajax which goes into some good detail about how to use the existing framework and modify it to work for Ajax/Json.
From my recent findings ...
If you set content type as "application/x-www-form-urlencoded" in the ajax request then you must put the AFRT in the data
If you set the content type to "application/json" then the token goes in the ajax "headers" property as described by haack.
On the server if you are checking for the form type token then using the vanilla AntiForgeryRequestTokenAttribute is ok but if you want to validate tokens sent in the header then you need to call the AntiForgeryToken.OnAuthorize ... or whatever, passing the token from the cookie (http context).
It aint easy but if it was everybody would be doing it :)

what is the use of anti-forgery token salt?

In ASP.NET MVC 1.0, there is a new feature for handling cross site request forgery security problem:
<%= Html.AntiForgeryToken() %>
[ValidateAntiForgeryToken]
public ViewResult SubmitUpdate()
{
// ... etc
}
I found the token generated in html form keep changing every time a new form is rendered.
I want to know how these token is generated? And when use some software to scan this site, it will report another security problem: Session fixed. Why? Since the token keep changed, how can this problem come ?
And there is another function, that is "salt" for the antiForgeryToken, but I really know what this used for, even through we don't use "salt" to generate the token, the token will changes all the time, so why have such function?
Lots of info on the AntiForgeryToken here: http://blog.codeville.net/2008/09/01/prevent-cross-site-request-forgery-csrf-using-aspnet-mvcs-antiforgerytoken-helper/
This is to prevent a Cross-Site Request Forgery (CSRF). It's pretty standard behavior to click 'Save' sumbit a form and perform some action on the server, i.e. save a user's details. How do you know the user submitting the form is the user they claim to be? In most cases you'd use some cookie or windows based auth.
What if an attacker lures you to a site which submits exactly the same form in a little hidden IFRAME? Your cookies get submitted intact and the server doesn't see the request as any different to a legit request. (As gmail has discovered: http://www.gnucitizen.org/blog/google-gmail-e-mail-hijack-technique/)
The anti-forgery token prevents this form of attack by creating a additional cookie token everytime a page is generated. The token is both in the form and the cookie, if the form and cookie don't match we have a CSRF attack (as the attacker wouldn't be able to read the anti-forgery token using the attack described above).
And what does the salt do, from the article above:
Salt is just an arbitrary string. A different salt value means a different anti-forgery token will be generated. This means that even if an attacker manages to get hold of a valid token somehow, they can’t reuse it in other parts of the application where a different salt value is required.
Update: How is the token generated? Download the source, and have a look at the AntiForgeryDataSerializer, AntiForgeryData classes.
You've ask a few unrelated problems:
I don't know why your security software is reporting 'session fixed'. Try reading the documentation that comes with the report
The anti-forgery token:
This is used (presumably) to validate that each request is valid. So consider that someone tries to present a link to the page ?x=1, if the token is not also passed, the request will be rejected. Further, it (may) prevent duplicate posting of the same item. If you click 'post' twice, the token will likely change (each request), and this case will be detected via something like:
Session["nextToken"] = token;
WriteToken(token);
...
if( !Request["nextToken"] == Session["nextToken"] ){
...
}
// note: order in code is slightly different, you must take the token
// before regenerating it, obviously
I think the term for this (the attack it protects) is called "CSRF" (Cross-Site Request Forgery), these days.

Resources