2017-05-28 136 views
0

我有一個現有的Spring WebMVC應用程序,並啓用了spring security。現在我想啓用Spring-Security CSRF檢查。Spring Security CSRF培訓模式

但我想讓它在訓練模式下運行。所以CSRF-Filter應該只記錄任何丟失的CSRF-Token,以便它可以不時地實施。

在CSRF處理的Spring-Security中是否有這樣的培訓模式?

我試圖實現自定義org.springframework.security.web.access.AccessDeniedHandler,並將其設置在WebSecurityConfigurerAdapter

http.exceptionHandling().accessDeniedHandler(new MyCustomAccessDeniedHandler()); 

但遺憾的是該請求不suceed因爲過濾器鏈停止。

我想我必須實現一個自定義CsrfFilter,但我該如何設置它?

有沒有一種簡單的方法來實施培訓模式? 任何建議或指針在正確的方向?

回答

1

由於CsrfFilterfinal,覆蓋或包裝它幾乎是不可能的。

但是,可能有幾種選擇來實現某種訓練模式 - 所有這些都有一定的缺點和可能的安全問題。所以要小心。

這裏是一個可能的解決方案:

  1. 提供了一個自定義CsrfFilter#accessDeniedHandlerAccessDeniedHandler,通過拋出一個自定義異常
  2. 使用自定義篩選權之前CsrfFilter處理處理任何丟失/錯誤的記號/日誌自定義異常並繼續鏈

下面是它可能是什麼樣子:

class MissingCsrfTokenException extends RuntimeException { 
} 

/** 
* Post process the CsrfFilter to use a custom AccessDeniedHandler 
*/ 
@Component 
class CsrfFilterBeanPostProcessor implements BeanPostProcessor { 

    @Override 
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { 
     if (bean instanceof CsrfFilter) { 
      CsrfFilter csrfFilter = (CsrfFilter) bean; 
      csrfFilter.setAccessDeniedHandler(new AccessDeniedHandler() { 

       /** 
       * Default CsrfFilter AccessDeniedHandler implementation (org.springframework.security.web.access.AccessDeniedHandler) 
       */ 
       AccessDeniedHandler delegate = new AccessDeniedHandlerImpl(); 

       @Override 
       public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException { 

        // test whether the request requires a valid CsrfToken (or is in training mode) 
        boolean inTrainingMode = ... 
        if (inTrainingMode) { 
         throw new MissingCsrfTokenException(); 
        } else { 
         // delegate to the default AccessDeniedHandler 
         delegate.handle(request, response, accessDeniedException); 
        } 
       } 
      }); 
     } 
     return bean; 
    } 

    @Override 
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { 
     return bean; 
    } 
} 

/** 
* Custom Filter that logs the token-exceptions and continues the chain. 
*/ 
class PreCsrfFilterFilter extends OncePerRequestFilter { 

    private Logger logger = LoggerFactory.getLogger(PreCsrfFilterFilter.class); 

    @Override 
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { 
     try { 
      filterChain.doFilter(request, response); 
     } catch (MissingCsrfTokenException ex) { 
      // log and continue the filter chain 
      logger.warn("No CSRF-Token found for {}", request.getRequestURI()); 
      filterChain.doFilter(request, response); 
     } 
    } 
} 

@Configuration 
@EnableWebSecurity 
class Config extends WebSecurityConfigurerAdapter { 

    @Override 
    protected void configure(HttpSecurity http) throws Exception { 
     http 
       .authorizeRequests() 
       .anyRequest().authenticated() 
       .and() 
       .formLogin().and() 
       .httpBasic() 
       .and() 
       // add the custom filter before the CsrfFilter 
       .addFilterBefore(new PreCsrfFilterFilter(), CsrfFilter.class); 
    } 
} 
+0

非常感謝!這個解決方案適用於我。我特別喜歡在過濾器鏈中捕捉異常的「技巧」。也感謝你指點我的BeanPostProcessor。我沒有意識到這一點。在我看來,僅僅爲了'CsrfFilter'而改變'AccessDeniedHandler'的做法比在我嘗試做的時候更全面。 – Tarator

+0

感謝您的反饋!很高興我能幫上忙! – fateddy