【问题标题】:AngularJS XSRF strategy does not honour cookie pathsAngularJS XSRF 策略不支持 cookie 路径
【发布时间】:2018-04-12 08:29:49
【问题描述】:

我在同一台服务器上运行了三个具有不同路径的 Spring Boot 应用程序。它们三个都暴露了 API 端点,其中一个还提供 Web 资源,例如 HTMLJavaScriptCSS

应用 1:

  1. 提供 UI 文件
  2. 提供 API 端点

应用 2

  1. 提供 API 端点

应用程序 3

  1. 提供 API 端点

到目前为止,我们只为应用程序 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 来自 application1,cookie 路径为 /application1。

到目前为止我的观察:

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

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

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

【问题讨论】:

  • 如果您需要更多详细信息,请告诉我。

标签: javascript java angularjs spring cookies


【解决方案1】:

我通过更改所有三个应用程序上的csrfTokenRepository 定义以及AngularJs 中的拦截器来根据请求URLs 读取那些cookies 并所有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);
            }
        };
    });
}]);

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

    • 有没有办法在不使用不同的 xsrf cookie 名称的情况下做到这一点...?
    • Cookie 是一个键/值对。如果您不想更改服务器端 cookie 名称。您始终可以通过在所有响应上添加拦截器来创建客户端 cookie。
    • 我知道的 cookie 有 httpOnlysecurepath 之类的属性...当您在 chrome 开发工具中打开应用程序选项卡的 cookie 部分时,您可以看到相同的内容
    猜你喜欢
    • 2013-03-04
    • 1970-01-01
    • 1970-01-01
    • 2021-01-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-02
    • 1970-01-01
    相关资源
    最近更新 更多