加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

angularjs – 标头和cookie中的CSRF令牌在请求中不匹配

发布时间:2020-12-17 18:04:03 所属栏目:安全 来源:网络整理
导读:我正在实现无状态API,我的组织说我需要防范CSRF攻击. 我在网上发现了这个人的解决方案,并决定尝试实施仅限客户端的方法:http://blog.jdriven.com/2014/10/stateless-spring-security-part-1-stateless-csrf-protection/ 以下是该网站为无状态解决方案所做的
我正在实现无状态API,我的组织说我需要防范CSRF攻击.

我在网上发现了这个人的解决方案,并决定尝试实施仅限客户端的方法:http://blog.jdriven.com/2014/10/stateless-spring-security-part-1-stateless-csrf-protection/

以下是该网站为无状态解决方案所做的事情(如果网站出现故障):

  1. CLIENT-SIDE GENERATED CSRF-TOKENS. Have the clients generate and send the same unique secret value in both a Cookie and a custom HTTP
    header. Considering a website is only allowed to read/write a Cookie
    for its own domain,only the real site can send the same value in both
    headers. Using this approach all your server has to do is check if
    both values are equal,on a stateless per request basis!

不幸的是它不起作用.我的标题值永远不会匹配我的cookie值,在某些情况下,我的标题似乎只是匹配cookie值的一个请求.

这是我的Angular代码:

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
             }
         };
     });
 }]);

以下是正在发送的CSRF值的一些示例.

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

这里发生了什么?我觉得我正在做那个家伙解决方案中的所有事情,但结果却是奇怪的结果.

解决方法

我最终没有发送客户端为每个请求创建的随机令牌.我无法让它发挥作用.

所以这就是我如何解决我的问题(有点):

(1)在每个请求(包括第一个请求)上,我从API返回一个名为“XSRF-TOKEN”的响应头中的cookie和一个与之关联的随机值.这是AngularJS在使用CSRF保护时默认查找的名称.

(2)收到该令牌后请求中发生的事情是,AngularJS使用该令牌的值在名为“XSRF-TOKEN”的请求头中发送cookie,并使用该令牌的值发送名为“X-XSRF-TOKEN”的头同样.

所以我的API处理随机化XSRF令牌,我的应用程序仍然是无状态的.我正在使用Web API,并使用全局过滤器来处理此XSRF令牌创建.下面是我的代码(在C#中).我不再在UI中处理任何代码(因为它似乎不需要):

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无状态的唯一方法.

在阅读AngularJS的$http文档后,我偶然发现了这个解决方案,该文档规定:

Cross Site Request Forgery (XSRF) Protection: XSRF is a technique by
which an unauthorized site can gain your user’s private data. Angular
provides a mechanism to counter XSRF. When performing XHR requests,
the $http service reads a token from a cookie (by default,XSRF-TOKEN)
and sets it as an HTTP header (X-XSRF-TOKEN). Since only JavaScript
that runs on your domain could read the cookie,your server can be
assured that the XHR came from JavaScript running on your domain. The
header will not be set for cross-domain requests.

To take advantage of this,your server needs to set a token in a
JavaScript readable session cookie called XSRF-TOKEN on the first HTTP
GET request. On subsequent XHR requests the server can verify that the
cookie matches X-XSRF-TOKEN HTTP header,and therefore be sure that
only JavaScript running on your domain could have sent the request.
The token must be unique for each user and must be verifiable by the
server (to prevent the JavaScript from making up its own tokens). We
recommend that the token is a digest of your site’s authentication
cookie with a salt for added security.

The name of the headers can be specified using the xsrfHeaderName and xsrfCookieName properties of either $httpProvider.defaults at config-time,$http.defaults at run-time,or the per-request config object.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读