Angular against Asp.Net WebApi, implement CSRF on the server Angular against Asp.Net WebApi, implement CSRF on the server asp.net asp.net

Angular against Asp.Net WebApi, implement CSRF on the server


Your code seems to be fine. The only thing is, you don't need most of the code you have as web.api runs "on top" of asp.net mvc, and latter has built in support for anti-forgery tokens.

In comments dbrunning and ccorrin express concerns that you only able to use build in AntiForgery tokens only when you are using MVC html helpers. It is not true. Helpers can just expose session based pair of tokens that you can validate against each other. See below for details.

UPDATE:

There is two methods you can use from AntiForgery:

  • AntiForgery.GetTokens uses two out parameters to return cookie token and form token

  • AntiForgery.Validate(cookieToken, formToken) validates if pair of tokens is valid

You totally can repurpose those two methods and use formToken as headerToken and cookieToken as actual cookieToken. Then just call validate on both within attribute.

Another solution is to use JWT (check eg MembershipReboot implementation)

This link shows how to use built in anti-forgery tokens with ajax:

<script>    @functions{        public string TokenHeaderValue()        {            string cookieToken, formToken;            AntiForgery.GetTokens(null, out cookieToken, out formToken);            return cookieToken + ":" + formToken;                        }    }    $.ajax("api/values", {        type: "post",        contentType: "application/json",        data: {  }, // JSON data goes here        dataType: "json",        headers: {            'RequestVerificationToken': '@TokenHeaderValue()'        }    });</script>void ValidateRequestHeader(HttpRequestMessage request){    string cookieToken = "";    string formToken = "";    IEnumerable<string> tokenHeaders;    if (request.Headers.TryGetValues("RequestVerificationToken", out tokenHeaders))    {        string[] tokens = tokenHeaders.First().Split(':');        if (tokens.Length == 2)        {            cookieToken = tokens[0].Trim();            formToken = tokens[1].Trim();        }    }    AntiForgery.Validate(cookieToken, formToken);}

Also take a look at this question AngularJS can't find XSRF-TOKEN cookie


I think your code is flawed. The whole idea around prevent CSRF is to prevent a unique token on each REQUEST, not each session. If the anti-forgery token is a session persisted value, the ability to perform CSRF still remains. You need to provide a unique token on each request...


This solution isn't secure since CSRF attacks are still possible as long as the Auth cookie is valid. Both the auth and the xsrf cookie will be sent to the server when an attacker makes you perform a request via another site, and therefore you are still vulnerable until the user does a "hard" logout.

Each request or session should have its own unique token to truly prevent CRSF attacks. But probably the best solution is to not use cookie based authentication but token based authentication such as OAuth. This prevents other websites from using your cookies to perform unwanted requests, since the tokens are used in http headers instead of cookies. And http headers are not automatically send.

  1. Token Based Authentication using ASP.NET Web API 2, Owin, and Identity
  2. AngularJS Token Authentication using ASP.NET Web API 2, Owin, and Identity

These excellent blog posts contain information of how to implement OAuth for WebAPI. The blog posts also contains great information of how to integrate it with AngularJS.

Another solution might be to disable CORS and only accept incoming requests from whitelisted domains. However this won't work for non-website applications, such as mobile and/or desktop clients. Next to that once your website is vulnerable to a XSS attack the attacker will still be able to forge requests on your behalve.