spring security CSRF 问题 Invalid CSRF Token 'null' was found on ......
1. 問題
前面幾篇博客?spring?security在集成spring boot的微服務(wù)框架后,實(shí)現(xiàn)了cas認(rèn)證和權(quán)限控制。但是在使用 postman 進(jìn)行調(diào)用的時(shí)候出現(xiàn)這個(gè)問題
HTTP Status 403-Invalid CSRF Token 'null' was found on the request parameter '_csrf' or header 'X-CSRF-TOKEN'.- 1
- 1
然后我上網(wǎng)查找了這個(gè)CSRF 資料整理如下:
Spring Security 4.0之后,引入了CSRF,默認(rèn)是開啟。不得不說,CSRF和RESTful技術(shù)有沖突。CSRF默認(rèn)支持的方法: GET|HEAD|TRACE|OPTIONS,不支持POST。
科普一下,什么是csrf,這是一個(gè)web應(yīng)用安全的問題,CSRF(Cross-site request forgery跨站請(qǐng)求偽造,也被稱為“One Click Attack” 或者Session Riding,攻擊方通過偽造用戶請(qǐng)求訪問受信任站點(diǎn)。
我們知道,客戶端與服務(wù)端在基于http協(xié)議在交互的數(shù)據(jù)的時(shí)候,由于http協(xié)議本身是無(wú)狀態(tài)協(xié)議,后來引進(jìn)了cookie的 方式進(jìn)行記錄服務(wù)端和客戶端的之間交互的狀態(tài)和標(biāo)記。cookie里面一般會(huì)放置服務(wù)端生成的session id(會(huì)話ID)用來識(shí)別客戶端訪問服務(wù)端過 程中的客戶端的身份標(biāo)記。
在跨域 (科普一下:同一個(gè)ip、同一個(gè)網(wǎng)絡(luò)協(xié)議、同一個(gè)端口,三者都滿足就是同一個(gè)域,否則就有跨域問題) 的情況下, session id可能會(huì)被惡意第三方劫持,此時(shí)劫持這個(gè)session id的第三方會(huì)根據(jù)這個(gè)session id向服務(wù)器發(fā)起請(qǐng)求,此時(shí)服務(wù)器收到這個(gè)請(qǐng)求會(huì) 認(rèn)為這是合法的請(qǐng)求,并返回根據(jù)請(qǐng)求完成相應(yīng)的服務(wù)端更新。
比較關(guān)鍵的一點(diǎn)是,
如果這個(gè)http請(qǐng)求是get方式發(fā)起的請(qǐng)求,意味著它只是訪問服務(wù)器 的資源,僅僅只是查詢,沒有更新服務(wù)器的資源,所以對(duì)于這類請(qǐng)求,spring security的防御策略是允許的,
如果這個(gè)請(qǐng)求是通過post請(qǐng)求發(fā)起的, 那么spring security是默認(rèn)攔截這類請(qǐng)求的,因?yàn)檫@類請(qǐng)求是帶有更新服務(wù)器資源的危險(xiǎn)操作,如果惡意第三方可以通過劫持session id來更新 服務(wù)器資源,那會(huì)造成服務(wù)器數(shù)據(jù)被非法的篡改,所以這類請(qǐng)求是會(huì)被Spring security攔截的,在默認(rèn)的情況下,spring security是啟用csrf 攔截功能的,這會(huì)造成,在跨域的情況下,post方式提交的請(qǐng)求都會(huì)被攔截?zé)o法被處理(包括合理的post請(qǐng)求),前端發(fā)起的post請(qǐng)求后端無(wú)法正常 處理,雖然保證了跨域的安全性,但影響了正常的使用,如果關(guān)閉csrf防護(hù)功能,雖然可以正常處理post請(qǐng)求,但是無(wú)法防范通過劫持session id的非法的post請(qǐng)求,所以spring security為了正確的區(qū)別合法的post請(qǐng)求,采用了token的機(jī)制。
在跨域的場(chǎng)景下,客戶端訪問服務(wù)端會(huì)首先發(fā)起get請(qǐng)求,這個(gè)get請(qǐng)求在到達(dá)服務(wù)端的時(shí)候,服務(wù)端的Spring security會(huì)有一個(gè)過濾 器 CsrfFilter去檢查這個(gè)請(qǐng)求,如果這個(gè)request請(qǐng)求的http header里面的X-CSRF-COOKIE的token值為空的時(shí)候,服務(wù)端就好自動(dòng)生成一個(gè) token值放進(jìn)這個(gè)X-CSRF-COOKIE值里面,客戶端在get請(qǐng)求的header里面獲取到這個(gè)值,如果客戶端有表單提交的post請(qǐng)求,則要求客戶端要 攜帶這個(gè)token值給服務(wù)端,在post請(qǐng)求的header里面設(shè)置_csrf屬性的token值,提交的方式可以是ajax也可以是放在form里面設(shè)置hidden 屬性的標(biāo)簽里面提交給服務(wù)端,服務(wù)端就會(huì)根據(jù)post請(qǐng)求里面攜帶的token值進(jìn)行校驗(yàn),如果跟服務(wù)端發(fā)送給合法客戶端的token值是一樣的,那么 這個(gè)post請(qǐng)求就可以受理和處理,如果不一樣或者為空,就會(huì)被攔截。由于惡意第三方可以劫持session id,而很難獲取token值,所以起到了 安全的防護(hù)作用。
2. 解決
原因找到了:spring Security 3默認(rèn)關(guān)閉csrf,Spring Security 4默認(rèn)啟動(dòng)了csrf。??
解決方案:?
如果不采用csrf,可禁用security的csrf
Java注解方式配置:
加上 .csrf().disable()即可。
修改前WebSecurityConfig.java
@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().antMatchers("/", "/home").permitAll().and().formLogin().loginPage("/login").permitAll().and().logout().logoutUrl("/logout").logoutSuccessUrl("/hello").permitAll();http.addFilterBefore(customizeFilterSecurityInterceptor, FilterSecurityInterceptor.class).csrf().disable();}- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
參考資料:?
http://blog.csdn.net/icanactnow2/article/details/53515844?
http://group.jobbole.com/24128/?
http://www.cnblogs.com/yjmyzz/p/customize-CsrfFilter-to-ignore-certain-post-http-request.html
總結(jié)
以上是生活随笔為你收集整理的spring security CSRF 问题 Invalid CSRF Token 'null' was found on ......的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: springboot 定制个性 bann
- 下一篇: springboot-springSec