我有三个Spring Boot应用程序在同一台服务器上运行,路径不同。所有这三个端点都公开了API端点,其中一个端点还提供了HTML
,JavaScript
和CSS
等网络资源。
申请1:
申请2
申请3
到目前为止,我们只对应用程序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。
到目前为止我的观察结果:
httpOnly=false
。 XSRF-TOKEN
个Cookie
他们自己的道路。 我怀疑这是Angular不尊重这条道路 cookie的属性,它与第一个带有名称的cookie一起使用
XSRF-TOKEN
。
有没有办法解决这个问题?
答案 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>
请注意,每个应用程序的cookieName
和headerName
都不同。 (请注意,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);
}
};
});
}]);