I've started using AntiForgeryToken in some of my forms to prevent cross site request forgery. However I am getting some weird behaviour and just wanted to clarify whether this is a bug or just me doing something wrong. I am using the Html.AntiForgeryToken() call in my form. I then use the [ValidateAntiForgeryToken] attribute in the action method that the form posts to. I'm not using a salt at this point.
My understanding is that Html.AntiForgeryToken() generates a hidden input with a name of __RequestVerificationToken and a cookie named __RequestVerificationToken_Lw__, which should both contain the same value.
The behaviour I am experiencing however is that:
The cookie always has the same value no matter how many times you
GET the page
The hidden input has a different value every time you GET the page
The ValidateAntiForgeryToken validates every time, even from a
different site in a CSRF scenario.
If I change the value of the hidden input in the foreign site, the
token doesn't validate (expected behaviour, but why does it validate
when the hidden input/cookie value is different?)
Anyone got any ideas?
For number 3, are you including the hidden field in your CSRF scenario?
The safety of the AntiForgeryToken is that the hidden input exists only in the page served by your domain, and cannot be copied or captured by another domain. If you have mocked up a test which passes the hidden input, then that is not a valid test.
I suggest you read this article from Phil Haack: Anatomy of a Cross-site Request Forgery Attack
Related
I'm attempting to get full page caching in Rails but I've hit a big of a snag with regards to CSRF - or perhaps just my understanding of it. I currently have the form_authenticity_token string stored in a cookie that JS can access and rewrite the header tags with.
There are two places I find tokens in my generated HTML:
1) In the head
<meta name="csrf-token" content="[hash]">
2) Inside a form's hidden input element
<input type="hidden" name="authenticity_token" value="[different hash]">
As indicated, these hashes are different from one another (in development mode where caching isn't enabled). Why are they different? Why is it that I can delete the head meta tags and leave the form input alone and the request is allowed? Yet when I delete the form input tag and leave the headers the request is rejected?
Effectively this means the head tags are useless, no? I can rewrite the form input tag to the value in my cookie just like I did with the header tags, but since they are different from one another I'm cautious as to what the end result might mean especially when it comes to full page caching.
Application Controller contains:
protect_from_forgery with: :exception
before_filter :csrf_cookie
def csrf_cookie
cookies['authenticity-token'.freeze] = {
value: form_authenticity_token,
expires: 1.day.from_now,
secure: (Rails.env.staging? || Rails.env.production?)
}
end
Browsing SO on another issue led me to the answer. In short, Rails helps out jQuery users by inserting the CSRF token into ajax requests automatically. It looks for it in the meta tags.
So having the CSRF token inside the form is useful for when submitting POST requests and having it in the head is useful for saving time/effort/mistakes with ajax requests.
Perhaps it's good to have it in both also because you may want to do an ajax request when there isn't a form present. If there IS a form and javascript is disabled, having it in the header doesn't do anyone any favours as it won't be included in the POST request.
As to why they are different, I can only guess it has something to do with the algorithm at the time of generation...but that's neither here nor there as both tokens work.
I'm testing my MVC3 web app for XSS attacks and I'm noticing a weird behavior with the default ValidateRequest in .Net
I have a form with a few text fields and when I enter a 'dangerous' string such as:
<img src=x onerror=alert(/XSS/.source)>
I see the "A potentially dangerous Request.Form was detected..." message pop up as expected.
My understanding is that this validation will automatically cancel the request and no changes will take place. However, when I refresh the page, I'm seeing that the text field in question now displays a value of 'ED7F9'
Something similar occurs if I try to save a value of <script>alert("hi")</script>. In this case, after the validation message, the remaining text in the field is: "alert("
Has anyone seen this before of have any clues as to why this is happening?
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.
There is a study here my co-worker took to my notice. Basically, that in-line form validation is a good thing.
But how would you do in-line multi-field form validation in MVC assuming you already have a "yield return" setup to return a list of form violations? Is the in-line validation only for primitive values like "a zip code should not include alpha characters?"
Would you submit some Javascript code to the client that checks that "this field and this field should be evaluated together firing this validation, and oh by the way, we are going to validate all fields again on a final submit?
Anyone have code example (C# and MVC) to illustrate handling in-line multi-field form validation using a remote repository (but not all fields at one time)?
I don't have any code but if I was going to do inline validation I would implement the validation sample in Nerd Dinner.
Clearly this would validate on a submit so not really useful to your question. However, if you couple it with jQuery then it does become useful.
Essentially I'd be doing a jQuery postback at key points, checking for validation errors, and then highlighting the errors to the user in the callback.
You can attach events to say the lost focus events of fields that have a certains style class or to all fields etc. Really quite extensible in that regard.
There are tons or samples on jQuery and how to post back etc.
I'd also still be doing the full validation check on postback as well just to catch anything that may have been missed.
Does this help?
I am trying to trace through why my ASP.NET MVC 2 validation isn't working, but I cant find enough about HOW it works to be able to do this.
I have followed the steps in this useful article by David Hayden which seems to be the best documentation currently out there, but nothing actually happens.
I get validation when i submit to the server (as I did since Preview 1 when i added data annotations to my model) but I'm not getting any client side validation.
How can i trace through to test? So far I have verified the following obvious things
MicrosoftMvcJQueryValidation.js and jquery.validate.min.js files are being downloaded
Html.ClientValidationEnabled = true
I cant see easily what is hooking up to which events to know quite how to debug it.
Here's what I've learnt:
MOST IMPORTANT
Your HTML Form must be created with the using directive, not just BeginForm and EndForm.
You must set Html.ClientValidationEnabled = true BEFORE you start your 'Form'
You must use Html.ValidationMessage for each field
You must set Html.ClientValidationEnabled = true on each partial control (ascx)
HOW IT WORKS (very simple overview)
When you do Html.BeginForm it creates a 'FormContext' in the ViewContext
When ValidationMessage helpers are used, metadata is put into the form context
When the form is disposed (by the using statement) it writes out all the validation code
MISC
I cannot seem to get validation working when I have a partial control, if that control uses a different model from the view that defines the Form.
You do NOT need to use Html.TextBoxFor or Html.ValidationMessageFor, you can use Html.TextBox and Html.ValidationMessage
In order for a field to be validated client-side you have to specify a call to Html.ValidationMessage/Html.ValidationMessageFor<> for the field (just like David did in the tutorial you linked) within the view. This is essentially a trigger to the client-side validation logic that you want to run validation for that field.
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.
Both of those requirements exist since you might not want the client-side validation to automatically validate every property on your model object, since some of them might not even be part of the form that you're wanting validated.