2017-09-09 82 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頭部。

這是一般情況。我不確定這是否適合您的特殊情況。

相關問題