Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Problems implementing ValidatingAntiForgeryToken attribute for Web API with MVC 4 RC

Tags:

I'm making JSON-based AJAX requests and, with MVC controllers have been very grateful to Phil Haack for his Preventing CSRF with AJAX and, Johan Driessen's Updated Anti-XSRF for MVC 4 RC. But, as I transition API-centric controllers to Web API, I'm hitting issues where the functionality between the two approaches is markedly different and I'm unable to transition the CSRF code.

ScottS raised a similar question recently which was answered by Darin Dimitrov. Darin's solution involves implementing an authorization filter which calls AntiForgery.Validate. Unfortunately, this code does not work for me (see next paragraph) and - honestly - is too advanced for me.

As I understand it, Phil's solution overcomes the problem with MVC AntiForgery when making JSON requests in the absence of a form element; the form element is assumed/expected by the AntiForgery.Validate method. I believe that this may be why I'm having problems with Darin's solution too. I receive an HttpAntiForgeryException "The required anti-forgery form field '__RequestVerificationToken' is not present". I am certain that the token is being POSTed (albeit in the header per Phil Haack's solution). Here's a snapshot of the client's call:

$token = $('input[name=""__RequestVerificationToken""]').val(); $.ajax({     url:/api/states",     type: "POST",     dataType: "json",     contentType: "application/json: charset=utf-8",     headers: { __RequestVerificationToken: $token } }).done(function (json) {     ... }); 

I tried a hack by mashing together Johan's solution with Darin's and was able to get things working but am introducing HttpContext.Current, unsure whether this is appropriate/secure and why I can't use the provided HttpActionContext.

Here's my inelegant mash-up.. the change is the 2 lines in the try block:

public Task<HttpResponseMessage> ExecuteAuthorizationFilterAsync(HttpActionContext actionContext, CancellationToken cancellationToken, Func<Task<HttpResponseMessage>> continuation) {     try     {         var cookie = HttpContext.Current.Request.Cookies[AntiForgeryConfig.CookieName];         AntiForgery.Validate(cookie != null ? cookie.Value : null, HttpContext.Current.Request.Headers["__RequestVerificationToken"]);     }     catch     {         actionContext.Response = new HttpResponseMessage         {             StatusCode = HttpStatusCode.Forbidden,             RequestMessage = actionContext.ControllerContext.Request         };         return FromResult(actionContext.Response);     }     return continuation(); } 

My questions are:

  • Am I correct in thinking that Darin's solution assumes the existence of a form element?
  • What's an elegant way to mash-up Darin's Web API filter with Johan's MVC 4 RC code?

Thanks in advance!

like image 867
DazWilkin Avatar asked Jul 30 '12 16:07

DazWilkin


People also ask

How AntiForgeryToken works in MVC?

To help prevent CSRF attacks, ASP.NET MVC uses anti-forgery tokens, also called request verification tokens. It verifies the tokens before accepting the request into ASP.NET MVC controller action which prevents the Cross Site Request Forgery.

What is AntiForgeryToken in web API?

Adding an AntiForgeryToken generates a Cryptographically valid hash at the server end which is split and a part is added as a hidden field, whereas the rest goes into a cookie. When data is posted, the Cookie and the Hidden Field are both sent back and if they are missing or they don't match, the POST is rejected.

What is an Anti-forgery?

Anti-forgery stands for “Act of copying or imitating things like a signature on a check, an official document to deceive the authority source for financial gains”. Now, in the case of web applications, it is termed as CSRF.


1 Answers

You could try reading from the headers:

var headers = actionContext.Request.Headers; var cookie = headers     .GetCookies()     .Select(c => c[AntiForgeryConfig.CookieName])     .FirstOrDefault(); var rvt = headers.GetValues("__RequestVerificationToken").FirstOrDefault(); AntiForgery.Validate(cookie != null ? cookie.Value : null, rvt); 

Note: GetCookies is an extension method that exists in the class HttpRequestHeadersExtensions which is part of System.Net.Http.Formatting.dll. It will most likely exist in C:\Program Files (x86)\Microsoft ASP.NET\ASP.NET MVC 4\Assemblies\System.Net.Http.Formatting.dll

like image 195
Darin Dimitrov Avatar answered Oct 30 '22 20:10

Darin Dimitrov