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.
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.
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.
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).
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.
#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.
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
Related
I am developing an Angular2 and integrating it with my ASP.NET MVC application.
To prevent CSRF attacks we have used Anti-Forgery Tokens in ASP.NET MVC helper function, which renders an input type inside the body.
Now I want to read this value and append it to the headers of all my ajax calls in my angular2 app.
I was not able to find a way how to read this value and pass to http wrapper service.
This is how the DOM looks:
<html>
<head></head>
<body>
<input name="__RequestVerificationToken" type="hidden" value="6fGBtLZmVBZ59oUad1Fr33BuPxANKY9q3Srr5y[...]" />
<my-app>
</my-app>
</body>
</html>
Thanks.
You can access it with jQuery selector:
<html>
<head></head>
<body>
<input name="__RequestVerificationToken" id="input_element" type="hidden" value="6fGBtLZmVBZ59oUad1Fr33BuPxANKY9q3Srr5y[...]" />
<my-app>
</my-app>
</body>
</html>
Component
checkValue(): string {
return $('#input_element').value();
}
This is not the most elegant way to do what you need, but it is the only one, since angular doesnt allow access to anything outside scope.
I actually used this to change css link in my tag located in tag.
But
Also consider the comments, that there is a better way to implement token based communication. You can actually save your token in localStorage after authentication procedure, or any other REST call. Take data from result of that REST call and localStorage.setItem('token', value).
You can create HttpInterceptor, custom one, where you can modify every REST call to have that token. Example of that:
https://medium.com/aviabird/http-interceptor-angular2-way-e57dc2842462
Thanks for your suggestions everyone.
So here is what I did after researching and from all of the above suggestion.
I created a window-ref service that returns me the window object and also has the getToken() method.
Then I inject this service in my http wrapper service.
The window ref service has the getToken() method that will check if the document object is present and if it finds the element with the provided name "__RequestVerificationToken" it will returns its value.
If the element is not present then blank value or null is returned.
While in the HttpWrapper service I check if the returned value from getToken() is blank then don't append the "__RequestVerificationToken" header else append it.
I followed this https://juristr.com/blog/2016/09/ng2-get-window-ref/ link for the window ref service.
I did'nt wanted to make another call to get the token from the server, because this call would obviously wont have any security token attached to its request headers and this would have made this call unsafe. An attacker could have easily called this method and got the token and successively attached it to next calls.
I have an MVC 4.0 site that uses AntiForgeryTokens to protect against CSRF attacks.
What I am finding is that I can reuse an old __RequestVerificationToken after new sessions have been opened.
I start with adding to the .cshtml
#Html.AntiForgeryToken()
I then decorate the Post Action method in the controller with
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult DoSomething(MyViewModel model)
{
}
I then do the following :-
Log in to admin site and scrape the __RequestVerificationToken value.
Log Out
Log Back In again (in theory there should now be a new token created)
Then submit the form below in a new tab in the same browser (see that I have used the token from the previous request).
<html>
<body>
<form action="http://adminsite.com/DoAction" method="POST">
<input type="hidden" name="id" value="26" />
<input name="__RequestVerificationToken" type="hidden" value="rt95zr0voZbgLga117YNBfwwLpTU8onGCDmZ4IQEisvhiNH_9ISTtsbDzIVgIkRUzwH81PpbrTRGK4MLSp3S3j-JMNjsJTL04TRl2J38rNz8KKomL98gLjEiJoXgMXFt0qaJ8tPaB4_PvGo8ATaxLcA2" />
<input type="submit" value="Submit request" />
</form>
</body>
</html>
What I find is that even though I have logged out and back in again, I am still able to use the old __RequestVerificationToken and I can successfully post the form.
After reading through the documentation (http://www.asp.net/mvc/overview/security/xsrfcsrf-prevention-in-aspnet-mvc-and-web-pages) there is no mention of invalidation of token.
My questions are :-
Shouldn't it now be invalid?
If not, why not?
Is there a way of making the __RequestVerificationToken invalid after logging out and back in again?
Why do we use .Validate and .Validatefor in validation?
I am using that, but I am not getting any error message in the UI.
Code
<div>
#{Html.BeginForm();}
#Html.TextBoxFor(x => x.LastName, new { id = "txtLastName" })
#{Html.Validate("LastName");}
#{Html.ValidateFor(x=>x.LastName);}
<input type="submit" id="btnSubmit" value="Submit" />
#{Html.EndForm();}
</div>
This behavior is intentional. Both these helpers just register corresponding parameters for client-side validation, without actually showing any message should the validation fail. However this message can still be displayed in a ValidationSummary.
If you want to show the message specific to the field/parameter, you should use ValidationMessage or ValidationMessageFor instead:
#Html.ValidationMessage("LastName")
#Html.ValidationMessageFor(x=>x.LastName)
If there are situations where you don't actually want a validation message to visually appear for each field (i.e. by using Html.ValidationMessage), but would rather allow a summary to be the sole source of validation error messages (i.e. by using Html.ValidationSummary), you still need some way to "trigger" the validation to occur for the specific fields you want it to. This can be achieved by using the Html.Validate/Html.ValidateFor<> methods within your view. Those helpers won't render anything, but will simply register the specified field for client-side validation.
See this post for answer How does validation in ASP.NET MVC 2 actually work?
I'm seeing an intermittent problem on our web site. Some users are trying to submit forms via GET when my form method is POST. The errors always come from IE users. I have noticed a few UA strings have a reference to "yie8," which I am assuming is Yahoo's IE8 package. I think the Yahoo! toolbar might have something against me, but I can't replicate the problem on IE7 with the toolbar installed. The problem happens not only on this form, but various others, many of which are submitted via Ajax using the jQuery form plugin load() function with an object parameter passed. This example isn't one of those.
A simple fix would be to just take out all of my AcceptVerb() attributes, but that would be totally lame. Anyone ever come across something like this or have any ideas with dealing with it?
Here's an example exception log entry.
We've got a Web problem! Exception thrown:
http://my.web.site/User.mvc/ResetPassword
Method: GET
User: <not logged in>
UserAgent: IE 7 (Mozilla/4.0 (compatible; MSIE 7.0;Windows NT 5.1;.NET CLR 1.1.4322;.NET CLR 2.0.50727;.NET CLR 3.0.04506.30))
Exception: System.Web.HttpException
Message: A public action method 'ResetPassword' could not be found on controller 'MyApp.Controllers.UserController'.
Here's the HTML as it is rendered to the browser.
<form action="/User.mvc/ResetPassword" class="standard-form small-form" method="post">
<fieldset>
<div class="row">
<label for="usernameTextBox">User Name</label>
<input type="text" name="username" id="usernameTextBox" />
</div>
<div class="row">
<label for="emailTextBox">Email Address</label>
<input type="text" name="email" id="emailTextBox" />
</div>
<div class="row">
<label> </label>
<input type="submit" value="Reset Password" />
</div>
</fieldset>
</form>
And here's the signature of my ResetPassword action.
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult ResetPassword(string username, string email)
(and yes, the email address is required to match the one we have on file)
Possibly an answer raising more questions than actual answers, but in the spirit of trying to help...
On the GET calls, are "username" and "email" querystring parameters actually supplied? (your IIS log file may be recording query strings, so check there). If so, then the answer of Ben S may well apply.
If your web site is internet facing, then these calls may just be spiders not playing nicely.
If your site is internal, I'd suspect a user is playing with "refresh".
Have you tracked the client IP addresses which raise these errors?
I don't think you can do anything about this. Some browser plug-ins/toolbars have a feature which allows changing forms from GET -> POST and vice-versa.
If your users are doing this, there isn't really anything you can do.
When website visitors misbehave like this, you have to ask yourself, "What are the chances this is a legitimate misunderstanding?" In my opinion, using the wrong HTTP method is not something a browser does because it's old or buggy or whatever. It's an invalid request, so send 'em a 405 and be done with it.
(I have heard of some browsers and plugins trying to 'preload' pages that are reachable from the current page, but it's a lame 'feature'. My answer is still to treat it as an invalid request.)
I'd say it isn't really your problem. You design your site to work as intended, you put your GET/POST restrictions on your methods (for security or other reasons).
If the user tries to get around your security with some advanced tools/plugins (such as GET/POST switches) it's not your concern. You might want, however, to add some custom error pages to handle those scenarios and warn the user accordingly.
What if I have ChangePassword form with hidden ID field of the user.
BadPerson knows id of GoodPerson. He opens Change Password form with FireBug, changes his Id to GoodPerson's Id, so password changes for GoodPerson.
Of course I can create some server logic that will prevent this, but I think there should be some out of the box solution, which throws if hidden field been changed, which I don't know.
EDIT
Ok, Change Password is a bad example. Any edit form where I have id in hidden field has same problem.
I agree with Darin that forms authentication will take care of the specific problem mentioned above (changing a password). This answer is for the more general question of making sure that a hidden field's value is not changed.
The best solution to this is to include another hidden field which contains a hash of the first hidden field's value. That way if the 1st hidden field is changed you will know it. The generated HTML looks something like this:
<input id="productId" name="productId" type="hidden" value="1" />
<input id="productId_sha1" name="productId_sha1" type="hidden" value="vMrgoclb/K+6EQ+6FK9K69V2vkQ=" />
This article shows how to do it and includes source code for an extension Html.SecuredHiddenField which will take care of the logic for you.
There is nothing that will let you know that a value of a hidden field's value has been changed or not. For a user to change his password it means that he needs to be authenticated. When using forms authentication the ID of the currently authenticated user is stored in an encrypted cookie which cannot be modified.
This is to say that you shouldn't use hidden fields for storing the currently connected user. Just use the built-in FormsAuthentication mechanism in ASP.NET and never store such information in hidden fields. The way ASP.NET knows that the value of the cookie hasn't been tampered with is that it signs it with the machineKey specified in the configuration.
There's an important rule that you should follow when dealing with security and authentication: always use built-in security mechanisms, never roll your own.