CSRF current in header and cookie does not match requests

I am implementing a stateless API and my organization says I need to protect against CSRF attacks.

I found this guy's solution online and decided to try using only the client approach: http://blog.jdriven.com/2014/10/stateless-spring-security-part-1-stateless-csrf-protection/

Here is what the site says for a stateless solution (in case the site does not work):

  1. RECEIVED BY CUSTOMERS. Ask clients to generate and send the same unique secret value in both the Cookie and the custom HTTP code header. Given that a website is read-only / cookie allowed for its own domain, only a real website can send the same value in both headers. Using this approach, all your server needs to do is check, both values ​​are equal, on a "statelessness" basis for each request!

Unfortunately, it does not work. The value of my header never matches my cookie value, and in some cases it seems that my header is just one request matching the cookie value.

Here is my Angular code:

 app.config(['$httpProvider', function ($httpProvider) {
     //fancy random token
     function b(a){return a?(a^Math.random()*16>>a/4).toString(16):([1e16]+1e16).replace(/[01]/g,b)};

     $httpProvider.defaults.xsrfHeaderName = 'X-CSRF-TOKEN';
     $httpProvider.defaults.xsrfCookieName = 'CSRF-TOKEN';

     $httpProvider.interceptors.push(function () {
         return {
             'request': function (config) {
                 document.cookie = 'CSRF-TOKEN=' + b();
                 return config
             }
         };
     });
 }]);

Here are some examples of CSRF values ​​to send.

 CSRF-TOKEN=d25cf03a985d575ad48a863eac91467666
 X-CSRF-TOKEN:fa1f165df8b27195a90f5e7841108f4e42

 CSRF-TOKEN=d25cf03a985d575ad48a863eac91467666
 X-CSRF-TOKEN:fa1f165df8b27195a90f5e7841108f4e42

 CSRF-TOKEN=9c8dd46ed06c250b707ac0cb80a08a23ac
 X-CSRF-TOKEN:d25cf03a985d575ad48a863eac91467666

 CSRF-TOKEN=eb407a0303c21173fe4d0ae03c97eaea6d
 X-CSRF-TOKEN:0cf066bf83e50b5c74cb932ab8a47c94e8

 CSRF-TOKEN=506355a940a2ac5b48f363712b34570d73
 X-CSRF-TOKEN:eb407a0303c21173fe4d0ae03c97eaea6d

? , , , .

+4
1

, . .

, ():

(1) ( ) API "XSRF-TOKEN" , . , AngularJS CSRF.

(2) , AngularJS cookie "XSRF-TOKEN", "X-XSRF-TOKEN" .

, API XSRF, - . Web API XSRF. ( #) . , ( ):

public class ValidateAntiForgeryToken : ActionFilterAttribute
{
    private const string XsrfCookieName = "XSRF-TOKEN";

    private const string XsrfHeaderName = "X-XSRF-TOKEN";

    private const string CsrfTokenSalt = "RANDOM SALT";


    public override void OnActionExecuting(HttpActionContext filterContext)
    {
        string requestMethod = filterContext.Request.Method.Method;

        Boolean isValid = true;

        if (requestMethod != "GET")
        {
            var headerToken = filterContext.Request.Headers.Where(x => x.Key.Equals(XsrfHeaderName, StringComparison.OrdinalIgnoreCase))
                .Select(x => x.Value).SelectMany(x => x).FirstOrDefault();

            var cookieToken = filterContext.Request.Headers.GetCookies().Select(x => x[XsrfCookieName]).FirstOrDefault();

            // check for missing cookie or header
            if (cookieToken == null || headerToken == null)
            {
                isValid = false;
            }

            // ensure that the cookie matches the header
            if (isValid && !String.Equals(headerToken, cookieToken.Value, StringComparison.OrdinalIgnoreCase))
            {
                isValid = false;
            }

            if (!isValid)
            {
                filterContext.Response = filterContext.Request.CreateResponse(HttpStatusCode.Unauthorized);
                filterContext.Response.ReasonPhrase = "Unauthorized to make that request.";
                return;
            }
        }

        base.OnActionExecuting(filterContext);
    }


    public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
    {
        string textToHash = RandomStringGeneration();
        string cookieText = HashService.HashText(textToHash, CsrfTokenSalt);

        var cookie = new CookieHeaderValue(XsrfCookieName, HttpUtility.UrlEncode(cookieText));

        /* don't use this flag if you're not using HTTPS */
        cookie.Secure = true;      
        cookie.HttpOnly = false; // javascript needs to be able to get this in order to pass it back in the headers in the next request

        /* if you have different environments on the same domain (which I did in one application using this code) make sure you set the path to be ApplicationPath of the request. Case sensitivity does matter in Chrome and IE, so be wary of that. */
        cookie.Path = "/";

        actionExecutedContext.Response.Headers.AddCookies(new[] { cookie });

        base.OnActionExecuted(actionExecutedContext);
    }
}

HashService.HashText():

public class HashService
{
    public static string HashText(string text, string salt)
    {
        SHA512Managed hashString = new SHA512Managed();

        byte[] textWithSaltBytes = Encoding.UTF8.GetBytes(string.Concat(text, salt));
        byte[] hashedBytes = hashString.ComputeHash(textWithSaltBytes);

        hashString.Clear();

        return Convert.ToBase64String(hashedBytes);
    }
}

, - . , , , cookie . , ( , ). XSRF , , . , , API .

$http AngularJS, :

(XSRF): XSRF - . Angular XSRF. XHR, $http cookie ( XSRF-TOKEN) HTTP- (X-XSRF-TOKEN). JavaScript, , cookie, , XHR JavaScript, . .

, JavaScript- XSRF-TOKEN HTTP- GET . XHR , cookie HTTP- X-XSRF-TOKEN, , JavaScript, , . ( JavaScript ). , cookie .

xsrfHeaderName xsrfCookieName $httpProvider.defaults config-time, $http.defaults .

0

All Articles