When working on an ASP.NET MVC project, you might get the following error message:
The required anti-forgery form field “__RequestVerificationToken” is not present
As the message says, this means that you’re missing the anti-forgery verification token. This token is used to prevent cross-site request forgery (CSRF) attacks. A CSRF attack is similar to a cross-site scripting (XSS) exploit but the other way around. In an XSS exploit, someone is using the fact that a user trusts a site and in a CSRF attack someone is using the fact is trusting a given user e.g. commands are sent to the server pretending to come from the user.
A very simple example of such an attack is to have a trusted user load a web page from a third party server and include a call to the target server e.g. in an image tag e.g.:
<img src="http://targetserver/importantfunction">
If the target server relies only on cookies for security, the user might have a still valid cookie and the server will not notice that it is actually an attack.
Of course this won’t work if you only accept POST requests but you could implement something like this using ajax.
To prevent this, the server has to implement an own protection mechanism instead of relying on the browser. One way to do it is to include in all forms a special random token linked to a cookie or the user session. When a call is received, if the form data do not contain this token (usually some random GUID), the request is rejected.
On the other hand, the token is present on the page so it’s not really secret. But because of the same-origin policy the attacker cannot read the token from the page (Cross-origin writes are allowed but cross-origin reads are typically not allowed).
In ASP.NET MVC you can define a method as requiring such a token by defining the ValidateAntiForgeryToken attribute e.g.:
[HttpPost] [ValidateAntiForgeryToken] public ActionResult MyAction(string id) { }
Note that when working with Orchard CMS even though your controller doesn’t define this attribute, the anti-forgery validation will happen.
When you use a form, you can handle the anti-forgery token by using the AntiForgeryToken() method of the Html helper e.g.:
@using (Html.BeginForm()) { @Html.AntiForgeryToken() <input ...> }
This will add an invisible field with the name __RequestVerificationToken in the form. This token will then be submitted with the form and checked on the server before processing the form.
Now I use a lot of ajax calls to the server using jquery e.g.:
$.ajax({ type: "POST", url: '@Url.Action("MyMethod", "MyController", new {area = "MyArea"})', dataType: "json", traditional: true, data: { "id": "12345678" }; }).done(function(result) { if (result) { // Do something } else { // Log or show an error message } return false; });
This call will fail with the error message in the title of this post. What you need to do is get the token from a form on the page and send it along the other call parameters. To fetch the value of the token, you can use jQuery as well:
$('input[name=__RequestVerificationToken]').val()
This will find the input field for the token (in a form on the page) and fetch the value. You then need to append it to the data sent to the server:
$.ajax({ type: "POST", url: '@Url.Action("MyMethod", "MyController", new {area = "MyArea"})', dataType: "json", traditional: true, data: { "id": "12345678", "__RequestVerificationToken": $('input[name=__RequestVerificationToken]').val() }; }).done(function(result) { if (result) { // Do something } else { // Log or show an error message } return false; });
The error is gone and the call is processed successfully. Now if you have many ajax calls on a page, it’s kind of a pain to add this to all calls. So you should rather create a helper function which will add the token to the data sent to the server:
function addRequestVerificationToken(data) { data.__RequestVerificationToken = $('input[name=__RequestVerificationToken]').val(); return data; };
You can then use it like this:
function addRequestVerificationToken(data) { data.__RequestVerificationToken = $('input[name=__RequestVerificationToken]').val(); return data; }; $.ajax({ type: "POST", url: '@Url.Action("MyMethod", "MyController", new {area = "MyArea"})', dataType: "json", traditional: true, data: addRequestVerificationToken( { "id": "12345678" } ); }).done(function(result) { if (result) { // Do something } else { // Log or show an error message } return false; });
If you use Orchard CMS you will see that the parts in an editor template are displayed within one form so you do not need to add a form. But when viewing content items, you usually do not require a form. So in this case you’ll have to add a form without submit, just to get the token:
@using (Html.BeginForm()) { @Html.AntiForgeryToken() }
Also if you use Orchard CMS instead of manually fetching the value of the verification token, you could also use the helper provided by Orchard:
function addAntiForgeryToken(data) { data.__RequestVerificationToken = "@Html.AntiForgeryTokenValueOrchard()"; return data; };