2017-09-09 78 views
0

我试图将CSRF/XSRF保护添加到我的应用程序,但遇到了奇怪的行为。所有获取请求都可以正常工作,但是在所有的post/put/delete中,我得到了403未授权。最奇怪的是,当我试图调试我的CSRF过滤器时,请求没有达到它,它们在之前的某个地方被拒绝。他们甚至没有达到我的认证过滤器,所以我无法弄清楚问题可能是什么。Spring Security和AngularJS的CSRF/XSRF保护

我的安全配置:

 @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; 
     } 

我不加过滤器,因为正如我所说,这些请求没有达到他们。但如果需要,我会完成我的问题。希望对你有所帮助,提前谢谢!

回答

0

非常感谢您的答复,他们确实帮助我找到了解决方案。如果未来有人会面临同样的问题,我想分享我的解决方案。

正如我以前SessionCreationPolicy.STATELESS并没有会话所以不是HttpSessionCsrfTokenRepository我不得不用CookieCsrfTokenRepositorywithHttpOnlyFalse(),让AngularJS读饼干的答案指出。

其结果是,我有一个这样的配置:

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

我希望我的回答将是有益的

0

假设您的配置/过滤器的其余部分正常工作,您因此面临此问题:SessionCreationPolicy.STATELESS

你可以看一看Spring CsrfFilter。您会发现它需要记住会话中每个用户的每个CSRF令牌的值,并且由于您没有使用会话,因此无法完成。

接下来要做什么 - 真的取决于你。有人说如果你的应用程序是无状态的,实际上不需要CSRF保护。 Spring docs表示CSRF攻击仍然相关。我认为这取决于你的认证机制。例如,您可能还想查看this nice article

希望它有帮助。

+0

为此我实现我的自定义CSRF过滤器,但我问题是,请求甚至没有达到它,这很奇怪 –

+0

@AnarSultanov,你可以请你分享你的过滤代码吗?虽然,没关系,因为你在* Spring的'CsrfFilter'之后添加了过滤器*。如果Springs过滤器不能匹配来自用户会话的令牌(它不能得到,因为没有会话)调用'accessDeniedHandler'并做'return'(打破过滤器链),这意味着它不会调用'filterChain.doFilter(request,response);',所以你的过滤器实际上不能被调用。如果你正在实现你自己的CSRF保护 - 那么,我想你应该通过调用'.csrf()。disable()'来禁用Spring的实现。 – Leffchik

+0

我发现可能是我的问题。我在Cookie中有XSRF-TOKEN,但角度不会将此标记的标题添加到请求中。现在我试图找出为什么以及如何解决这个问题。 –

0

原则上,Spring中的CSRF机制将CSRF令牌存储在仅HTTP cookie中。因为JavaScript不能访问HTTP cookie的唯一,你需要告诉春天只禁用HTTP:

.and().csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()); 

然后你可以阅读角的cookie并把它添加到每个请求的XSRF-Token头部。

这是一般情况。我不确定这是否适合您的特殊情况。

相关问题