Angularjs CSRF/XSRF保护弹簧安全性和角度
我试图将CSRF/XSRF保护添加到我的应用程序中,但遇到了奇怪的行为。所有get请求都可以正常工作,但是在所有post/put/delete上,我得到了403个未经授权的请求。最奇怪的是,当我试着调试我的CSRF过滤器时,请求没有到达它,它们在早些时候被拒绝了。它们甚至没有到达我的身份验证过滤器,因此我无法找出问题所在 我的安全配置:Angularjs CSRF/XSRF保护弹簧安全性和角度,angularjs,spring,spring-security,csrf,x-xsrf-token,Angularjs,Spring,Spring Security,Csrf,X Xsrf Token,我试图将CSRF/XSRF保护添加到我的应用程序中,但遇到了奇怪的行为。所有get请求都可以正常工作,但是在所有post/put/delete上,我得到了403个未经授权的请求。最奇怪的是,当我试着调试我的CSRF过滤器时,请求没有到达它,它们在早些时候被拒绝了。它们甚至没有到达我的身份验证过滤器,因此我无法找出问题所在 我的安全配置: @Override public void configure(HttpSecurity http) throws Except
@Override
public void configure(HttpSecurity http) throws Exception {
http
...
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.addFilterBefore(new StatelessAuthenticationFilter(tokenAuthenticationService()), UsernamePasswordAuthenticationFilter.class)
.addFilterAfter(new CsrfHeaderFilter(), CsrfFilter.class)
.csrf().csrfTokenRepository(csrfTokenRepository());
}
private CsrfTokenRepository csrfTokenRepository() {
HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
repository.setHeaderName("X-XSRF-TOKEN");
return repository;
}
我没有添加过滤器,因为正如我所说,请求没有到达它们。但如果需要,我会完成我的问题。希望您的帮助,提前谢谢 假设其余的配置/过滤器工作正常,您将面临这个问题,因为:
SessionCreationPolicy.STATELESS
您可以在弹簧罩下查看CsrfFilter
。您将看到,它需要记住会话中每个用户的每个CSRF令牌的值,并且由于您没有使用会话,因此无法执行此操作
下一步该怎么办?这完全取决于你。有些人说,如果你的应用程序是无状态的,实际上就不需要CSRF保护。说CSRF攻击仍然相关。我认为这取决于你的认证机制
例如,您可能还想看看
希望能有所帮助。假设您的其他配置/过滤器工作正常,您将因此而面临此问题:
SessionCreationPolicy.STATELESS
您可以在弹簧罩下查看CsrfFilter
。您将看到,它需要记住会话中每个用户的每个CSRF令牌的值,并且由于您没有使用会话,因此无法执行此操作
下一步该怎么办?这完全取决于你。有些人说,如果你的应用程序是无状态的,实际上就不需要CSRF保护。说CSRF攻击仍然相关。我认为这取决于你的认证机制
例如,您可能还想看看
希望有帮助。原则上,Spring中的CSRF机制将CSRF令牌存储在仅HTTP的cookie中。由于JavaScript无法访问仅限HTTP的cookie,因此需要告诉spring仅禁用HTTP:
.and().csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
然后,您可以从Angular读取cookie,并随每个请求将其添加到XSRF-TOKEN头中
这是一般情况。我不确定这是否适合你的特殊情况 原则上,Spring中的CSRF机制将CSRF令牌存储在仅HTTP的cookie中。由于JavaScript无法访问仅限HTTP的cookie,因此需要告诉spring仅禁用HTTP:
.and().csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
然后,您可以从Angular读取cookie,并随每个请求将其添加到XSRF-TOKEN头中
这是一般情况。我不确定这是否适合你的特殊情况 非常感谢您的回答,他们真的帮助我找到了解决方案。如果将来有人会面临同样的问题,我想分享我的解决方案 如回答中所述,我使用了
SessionCreationPolicy.STATELESS
并且没有会话,因此我必须使用CookiesRftokenRepository
和和httponlyFalse()
来代替HttpSessionsRftokenRepository,以允许AngularJS读取cookies
因此,我的配置如下:
@Override
public void configure(HttpSecurity http) throws Exception {
http
...
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.addFilterBefore(new StatelessAuthenticationFilter(tokenAuthenticationService()), UsernamePasswordAuthenticationFilter.class)
.addFilterAfter(new CsrfHeaderFilter(), CsrfFilter.class)
.csrf().csrfTokenRepository(csrfTokenRepository());
}
如果有人对CsrfHeaderFilter的外观感兴趣:
public class CsrfHeaderFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class.getName());
if (csrf != null) {
Cookie cookie = WebUtils.getCookie(request, "XSRF-TOKEN");
String token = csrf.getToken();
if (cookie==null || token!=null && !token.equals(cookie.getValue())) {
cookie = new Cookie("XSRF-TOKEN", token);
cookie.setPath("/");
response.addCookie(cookie);
}
}
filterChain.doFilter(request, response);
}
}
我的第二个问题是CORS。AngularJS文档说:
“不会为跨域请求设置标头。”
为了解决这个问题,我必须使用HTTP拦截器:
.factory('XsrfInterceptor', function ($cookies) {
return {
request: function (config) {
var headerName = 'X-XSRF-TOKEN';
var cookieName = 'XSRF-TOKEN';
config.headers[headerName] = $cookies.get(cookieName);
return config;
}
};
});
.config(['$httpProvider', function($httpProvider) {
$httpProvider.interceptors.push('XsrfInterceptor');
}]);
我希望我的答案会有用。非常感谢你的答案,它们确实帮助我找到了解决方案。如果将来有人会面临同样的问题,我想分享我的解决方案
如回答中所述,我使用了SessionCreationPolicy.STATELESS
并且没有会话,因此我必须使用CookiesRftokenRepository
和和httponlyFalse()
来代替HttpSessionsRftokenRepository,以允许AngularJS读取cookies
因此,我的配置如下:
@Override
public void configure(HttpSecurity http) throws Exception {
http
...
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.addFilterBefore(new StatelessAuthenticationFilter(tokenAuthenticationService()), UsernamePasswordAuthenticationFilter.class)
.addFilterAfter(new CsrfHeaderFilter(), CsrfFilter.class)
.csrf().csrfTokenRepository(csrfTokenRepository());
}
如果有人对CsrfHeaderFilter的外观感兴趣:
public class CsrfHeaderFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class.getName());
if (csrf != null) {
Cookie cookie = WebUtils.getCookie(request, "XSRF-TOKEN");
String token = csrf.getToken();
if (cookie==null || token!=null && !token.equals(cookie.getValue())) {
cookie = new Cookie("XSRF-TOKEN", token);
cookie.setPath("/");
response.addCookie(cookie);
}
}
filterChain.doFilter(request, response);
}
}
我的第二个问题是CORS。AngularJS文档说:
“不会为跨域请求设置标头。”
为了解决这个问题,我必须使用HTTP拦截器:
.factory('XsrfInterceptor', function ($cookies) {
return {
request: function (config) {
var headerName = 'X-XSRF-TOKEN';
var cookieName = 'XSRF-TOKEN';
config.headers[headerName] = $cookies.get(cookieName);
return config;
}
};
});
.config(['$httpProvider', function($httpProvider) {
$httpProvider.interceptors.push('XsrfInterceptor');
}]);
我希望我的答案会有用。因此,我实现了定制的CSRF过滤器,但我的问题是,请求甚至无法到达它。这很奇怪。@AnarSultanov,你能分享一下你的过滤器代码吗?尽管如此,这并不重要,因为您在Spring的CsrfFilter
之后添加了过滤器。如果Springs筛选器无法匹配来自用户会话的令牌(由于没有会话,它无法获取令牌),它将调用accessDeniedHandler
,并执行return
(断开筛选器链),这意味着它没有调用filterChain.doFilter(请求,响应)代码>,因此您的筛选器实际上无法在之后调用。如果您正在实现自己的CSRF保护,那么,我想,您应该通过调用.CSRF().disable()
来禁用Spring的实现。我发现了我的问题所在。我在Cookie中有XSRF-TOKEN,但不会将带有此令牌的头添加到请求中。现在我正试图找出原因以及如何解决这个问题。出于这个原因,我实现了我的定制CSRF过滤器,但我的问题是,请求甚至无法到达它。这很奇怪。@AnarSultanov,你能分享一下你的过滤器代码吗?尽管如此,这并不重要,因为您在Spring的CsrfFilter
之后添加了过滤器。如果Springs筛选器无法匹配来自用户会话的令牌(由于没有会话,它无法获取令牌),它将调用accessDeniedHandler
,并执行return
(断开筛选器链),这意味着它没有调用filterChain.doFilter(请求,响应)代码>,因此您的筛选器无法实际运行