Spring Security :HTTP Status 403-Invalid CSRF Token 'null' was found on the request parameter '_csrf' or header 'X-CSRF-TOKEN'.前端
緣由:
1.Spring Security 4.0以後,引入了CSRF,默認是開啓。CSRF默認支持的方法: GET|HEAD|TRACE|OPTIONS,不支持POST。
Spring Security 3默認關閉csrf,Spring Security 4默認啓動了csrf。 web
2.什麼是csrf:
這是一個web應用安全的問題,CSRF(Cross-site request forgery跨站請求僞造,也被稱爲「One Click Attack」 或者Session Riding,攻擊方經過僞造用戶請求訪問受信任站點。
咱們知道,客戶端與服務端在基於http協議在交互的數據的時候,因爲http協議自己是無狀態協議,後來引進了cookie的 方式進行記錄服務端和客戶端的之間交互的狀態和標記。cookie裏面通常會放置服務端生成的session id(會話ID)用來識別客戶端訪問服務端過 程中的客戶端的身份標記。ajax
在跨域 (科普一下:同一個ip、同一個網絡協議、同一個端口,三者都知足就是同一個域,不然就有跨域問題) 的狀況下, session id可能會被惡意第三方劫持,此時劫持這個session id的第三方會根據這個session id向服務器發起請求,此時服務器收到這個請求會 認爲這是合法的請求,並返回根據請求完成相應的服務端更新。spring
若是這個http請求是get方式發起的請求,意味着它只是訪問服務器 的資源,僅僅只是查詢,沒有更新服務器的資源,因此對於這類請求,spring security的防護策略是容許的;後端
若是這個請求是經過post請求發起的, 那麼spring security是默認攔截這類請求的,由於這類請求是帶有更新服務器資源的危險操做,若是惡意第三方能夠經過劫持session id來更新 服務器資源,那會形成服務器數據被非法的篡改,因此這類請求是會被Spring security攔截的,在默認的狀況下,spring security是啓用csrf 攔截功能的,這會形成,在跨域的狀況下,post方式提交的請求都會被攔截沒法被處理(包括合理的post請求),前端發起的post請求後端沒法正常 處理,雖然保證了跨域的安全性,但影響了正常的使用,若是關閉csrf防禦功能,雖然能夠正常處理post請求,可是沒法防範經過劫持session id的非法的post請求,因此spring security爲了正確的區別合法的post請求,採用了token的機制。跨域
在跨域的場景下,客戶端訪問服務端會首先發起get請求,這個get請求在到達服務端的時候,服務端的Spring security會有一個過濾 器 CsrfFilter去檢查這個請求,若是這個request請求的http header裏面的X-CSRF-COOKIE的token值爲空的時候,服務端就好自動生成一個 token值放進這個X-CSRF-COOKIE值裏面,客戶端在get請求的header裏面獲取到這個值,若是客戶端有表單提交的post請求,則要求客戶端要 攜帶這個token值給服務端,在post請求的header裏面設置_csrf屬性的token值,提交的方式能夠是ajax也能夠是放在form裏面設置hidden 屬性的標籤裏面提交給服務端,服務端就會根據post請求裏面攜帶的token值進行校驗,若是跟服務端發送給合法客戶端的token值是同樣的,那麼 這個post請求就能夠受理和處理,若是不同或者爲空,就會被攔截。因爲惡意第三方能夠劫持session id,而很難獲取token值,因此起到了 安全的防禦做用。安全
解決方案:
若是不採用csrf,可禁用security的csrf
Java註解方式配置:加上 .csrf().disable()服務器
public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests().antMatchers("/").access("hasRole('READER')") .antMatchers("/*").permitAll() .and() .formLogin() .loginPage("/login") .failureUrl("/login?error=true"); http.csrf().disable(); } }