AngularJS XSRF策略不支持cookie路径

时间:2017-10-31 08:26:36

标签: javascript java angularjs spring cookies

我有三个Spring Boot应用程序在同一台服务器上运行,路径不同。所有这三个端点都公开了API端点,其中一个端点还提供了HTMLJavaScriptCSS等网络资源。

申请1:

  1. 提供UI文件
  2. 提供API端点
  3. 申请2

    1. 提供API端点
    2. 申请3

      1. 提供API端点
      2. 到目前为止,我们只对应用程序1启用了CSRF验证。这与org.springframework.security.web.csrf.CookieCsrfTokenRepository配合得很好。我们将XSRF-TOKEN作为Cookie发送,angularJs会在每个请求的标头中发回X-XSRF-TOKEN

        现在我们计划将XSRF引入其他两个应用程序,方法与应用程序1相同。

        但是我们遇到了问题。 AngularJs从应用程序1发送XSRF-TOKEN,并对所有三个应用程序使用相同的令牌,而每个应用程序每个应用程序都有自己的TOKEN cookie(应用程序路径)。

        这导致其他两项服​​务的CSRF验证失败。

        以下是我使用的配置。

        Spring-boot version     : 1.5.3
        Angular version         : 1.3.18
        
          <beans:bean id="csrfTokenRepository" class="org.springframework.security.web.csrf.CookieCsrfTokenRepository">
            <beans:property name="cookieHttpOnly" value="false" />
          </beans:bean>
        

        我得到的错误

        {
          "timestamp": 1509437659613,
          "status": 403,
          "error": "Forbidden",
          "message": "Invalid CSRF Token '2fa60cb2-803f-4b2b-a1d6-7e10e56ca649' was found on the request parameter '_csrf' or header 'X-XSRF-TOKEN'.",
          "path": "/application2/posturl/path"
        }
        

        此处令牌2fa60cb2-803f-4b2b-a1d6-7e10e56ca649来自带有cookie路径/ application1的application1。

        到目前为止我的观察结果:

        1. 我检查过并确保所有三个应用程序都设置了cookie 是httpOnly=false
        2. 我可以看到所有三个应用程序都有 他们在chrome开发者控制台中使用自己的XSRF-TOKEN个Cookie 他们自己的道路。
        3. 我没有在角端写一行 改变其默认行为。
        4. 所有三个应用程序都在同一IP和端口上作为WAR文件运行。
        5.   

          我怀疑这是Angular不尊重这条道路   cookie的属性,它与第一个带有名称的cookie一起使用   XSRF-TOKEN

          有没有办法解决这个问题?

2 个答案:

答案 0 :(得分:1)

您必须更改Angularjs和Spring的默认行为 在Spring Security上,您应该更改xrsft cookie名称(3个应用程序中的每一个都有一个不同)。

在Angular上,您可以在每个请求上添加一个拦截器,以便在标头中动态设置正确的cookie值(通过$cookies.get(key)检索它);

答案 1 :(得分:0)

我通过更改所有三个应用程序上的csrfTokenRepository定义以及AngularJs中的拦截器来解决问题,以便根据请求cookies读取所有URLs Cookie被设置为相同的Path

<beans:bean id="csrfTokenRepository" 
    class="org.springframework.security.web.csrf.CookieCsrfTokenRepository">
    <beans:property name="cookieHttpOnly" value="false" />
    <beans:property name="cookiePath" value="/" />
    <beans:property name="cookieName" value="APP-1-XSRF-TOKEN" />
    <beans:property name="headerName" value="APP-1-X-XSRF-TOKEN" />
</beans:bean>

请注意,每个应用程序的cookieNameheaderName都不同。 (请注意,headerName在每个应用程序中都不一样。但我更喜欢这种方式。)

AngularJs拦截器看起来像这样。

app.config(['$httpProvider', function ($httpProvider) {
    $httpProvider.interceptors.push(function ($q) {
        return {
            'request': function (config) {
                var readCookie = function (k, r) {
                    return (r = RegExp('(^|; )' + encodeURIComponent(k) + '=([^;]*)').exec(document.cookie)) ? r[2] : null; //CafePasta from https://stackoverflow.com/a/5639455/2557818
                };
                if (config.url.indexOf("/app1") > 0) {
                    config.headers['APP-1-X-XSRF-TOKEN'] = readCookie("APP-1-XSRF-TOKEN", document.cookie);
                } else if (config.url.indexOf("/app2") > 0) {
                    config.headers['APP-2-X-XSRF-TOKEN'] = readCookie("APP-2-XSRF-TOKEN", document.cookie);
                } else if (config.url.indexOf("/app3") > 0) {
                    config.headers['APP-3-X-XSRF-TOKEN'] = readCookie("APP-3-XSRF-TOKEN", document.cookie);
                }
                return config || $q.when(config);
            }
        };
    });
}]);