Spring?Security中的CORS詳解
一、CORS是什么
CORS(Cross-Origin Resource Sharing,跨源/域資源共享 )是一個(gè)W3C標(biāo)準(zhǔn),一種允許當(dāng)前域(domain)的資源(比如html/js/web service)被其他域(domain)的腳本(比如AJAX)請(qǐng)求訪問(wèn)的機(jī)制,通常由于同源安全策略,瀏覽器會(huì)禁止這種跨域請(qǐng)求。
CORS需要瀏覽器和服務(wù)器同時(shí)支持。目前,所有瀏覽器都支持該功能,IE 瀏覽器不能低于 IE10。
整個(gè)CORS通信過(guò)程,都是瀏覽器自動(dòng)完成,不需要用戶參與。對(duì)于開發(fā)者來(lái)說(shuō),CORS通信與同源的AJAX通信沒(méi)有差別,代碼完全一樣。瀏覽器一旦發(fā)現(xiàn)AJAX請(qǐng)求跨源,就會(huì)自動(dòng)添加一些附件的頭信息,有時(shí)還會(huì)多處一次附件的請(qǐng)求,但用戶不會(huì)有感覺(jué)。
因此,實(shí)現(xiàn)CORS通信的關(guān)鍵是服務(wù)器。只要服務(wù)器實(shí)現(xiàn)了CORS功能(響應(yīng)報(bào)文包括了正確的CORS響應(yīng)頭),就可以被跨源訪問(wèn)(可以指定個(gè)別域或全部域)。
二、同源安全策略
說(shuō)到跨域請(qǐng)求,就不得不說(shuō)一下“同源安全策略”了,如果沒(méi)有這個(gè)策略的存在,也就沒(méi)有這么多事了,但是,這樣可能會(huì)造成你在網(wǎng)站進(jìn)行一些操作時(shí)存在風(fēng)險(xiǎn)。
同源策略是一個(gè)重要的安全策略,它用于限制一個(gè)源/域的文檔或它加載的腳本是否能與另一個(gè)源/域的資源進(jìn)行交互。它能幫助阻隔惡意文檔,減少可能被攻擊的媒介。
出于安全性,瀏覽器會(huì)限制腳本內(nèi)發(fā)起的跨域HTTP請(qǐng)求,例如常見的 XHR、Fetch API 都遵循同源策略。
如果兩個(gè) URL 的協(xié)議(Protocol)、主機(jī)(Host)、端口(Port,如果有指定的話)都相同的話,那么這兩個(gè) URL 是同源的,否則是不同源的。
當(dāng)瀏覽器中打開的某個(gè)網(wǎng)頁(yè),有腳本執(zhí)行了跨域請(qǐng)求,那么,瀏覽器的“同源安全策略”就會(huì)介入,大致流程如下:
瀏覽器直接發(fā)出CORS請(qǐng)求,也就是在頭信息之中,增加一個(gè)Origin
字段。這個(gè)字段代表本次請(qǐng)求來(lái)自哪個(gè)源(協(xié)議 + 主機(jī) + 端口),服務(wù)器會(huì)根據(jù)這個(gè)值,決定是否同意這次請(qǐng)求。前面的流程是對(duì)于HTTP簡(jiǎn)單請(qǐng)求,如果是HTTP非簡(jiǎn)單請(qǐng)求,則會(huì)在正式請(qǐng)求前,增加一次預(yù)檢請(qǐng)求。
如果Origin
指定的源,不在許可范圍內(nèi)(服務(wù)器端CORS功能指定),服務(wù)器會(huì)返回一個(gè)正確的HTTP回應(yīng)。瀏覽器發(fā)現(xiàn),這個(gè)回應(yīng)的頭信息沒(méi)有包含Access-Control-Allow-Origin
字段,就知道出錯(cuò)了,從而拋出一個(gè)錯(cuò)誤,被XMLHttpRequest
的onerror
回調(diào)函數(shù)捕獲。注意,這種錯(cuò)誤無(wú)法通過(guò)狀態(tài)識(shí)別,因?yàn)镠TTP回應(yīng)的狀態(tài)碼有可能是 200
。
拋出的錯(cuò)誤為“has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.”,如下:
三、Spring Security中CORS的開啟
在Spring框架中,我們可以在引入Spring Security依賴后,對(duì)Security的HttpSecurity進(jìn)行設(shè)置,來(lái)開啟CORS(跨域/源資源共享),同時(shí)能指定只被部分域/源、部分方法、部分頭部信息訪問(wèn)資源。
Spring框架提供了CorsFilter,是為了在基于filter的安全框架(如Spring Security)上面支持CORS,或者在使用其他不支持CORS的庫(kù)上支持CORS。
//(Security6.2.4寫法)先創(chuàng)建一個(gè)普通JAVA類,如SecurityConfig.java,實(shí)現(xiàn)如下3個(gè)Bean。 @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http.authorizeHttpRequests( (authz) -> authz .anyRequest().authenticated()) .httpBasic(withDefaults()) .formLogin(withDefaults()) .csrf((csrf)->csrf.disable()) .cors(withDefaults()); //開啟CORS(跨域/源資源共享) return http.build(); } @Autowired //自動(dòng)裝配參數(shù)configurationSource(下方的Bean) @Bean public CorsFilter corsFilter(UrlBasedCorsConfigurationSource configurationSource){ return new CorsFilter(configurationSource); } // 也可以將方法內(nèi)的實(shí)現(xiàn)整合到上面的corsFilter方法體內(nèi) @Bean public UrlBasedCorsConfigurationSource configurationSource(){ UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); CorsConfiguration corsConfiguration = new CorsConfiguration(); corsConfiguration.setAllowCredentials(true); corsConfiguration.addAllowedHeader("*"); corsConfiguration.addAllowedMethod("*"); corsConfiguration.addAllowedOriginPattern("http://localhost*"); //新版本寫法 //corsConfiguration.addAllowedOrigin("*"); //老版本寫法 source.registerCorsConfiguration("/**",corsConfiguration); return source; }
四、其它處理方法
1、Spring注解
原理:自Spring Framework 4.2開始,CORS請(qǐng)求(包括OPTIONS method)會(huì)被自動(dòng)分發(fā)到各種注冊(cè)過(guò)的HandlerMappings。它們會(huì)處理CORS的preflight請(qǐng)求,會(huì)攔截CORS簡(jiǎn)單和實(shí)際請(qǐng)求,以便基于你指定的CORS配置,添加相關(guān)的CORS響應(yīng)頭(如 Access-Control-Allow-Origin
)。
實(shí)現(xiàn):在@RequestMapping注解過(guò)的controller method上面添加@CrossOrigin注解,表示已開啟CORS。
@CrossOrigin(origins = "http://domain2.com", maxAge = 3600) //括號(hào)內(nèi)為指定的CORS配置 @RestController @RequestMapping("/account") public class AccountController { @CrossOrigin("http://domain2.com") //同時(shí)使用controller級(jí)別和method級(jí)別的CORS配置,Spring會(huì)將二者的attributes結(jié)合起來(lái),創(chuàng)建出融合的CORS配置。 @RequestMapping("/{id}") public Account retrieve(@PathVariable Long id) { // ... } }
除了基于注解@CrossOrigin的配置(細(xì)粒度),還可以定義全局的CORS配置。類似于使用filters,但可以定義在Spring MVC中,并與細(xì)粒度的@CrossOrigin配置相配合。
2、JSONP(JSON with Padding)
原理:利用<script>標(biāo)簽不受瀏覽器同源策略限制的特性,通過(guò)動(dòng)態(tài)插入<script>標(biāo)簽的方式實(shí)現(xiàn)跨域數(shù)據(jù)訪問(wèn)。
實(shí)現(xiàn):客戶端創(chuàng)建一個(gè)<script>標(biāo)簽,將請(qǐng)求后端的接口URL拼接一個(gè)回調(diào)函數(shù)名稱作為參數(shù)傳給后端,并設(shè)置給<script>標(biāo)簽的src屬性。后端接收到請(qǐng)求后,將數(shù)據(jù)和回調(diào)函數(shù)名稱拼接成函數(shù)調(diào)用的形式返回??蛻舳嗽诮邮盏巾憫?yīng)后,會(huì)執(zhí)行這個(gè)回調(diào)函數(shù),從而獲取到后端返回的數(shù)據(jù)。
3、使用代理服務(wù)器
原理:通過(guò)搭建一個(gè)代理服務(wù)器來(lái)轉(zhuǎn)發(fā)客戶端的請(qǐng)求,代理服務(wù)器與目標(biāo)服務(wù)器進(jìn)行通信,然后將返回的數(shù)據(jù)再轉(zhuǎn)發(fā)給客戶端。由于客戶端和代理服務(wù)器、代理服務(wù)器和目標(biāo)服務(wù)器之間的通信都在服務(wù)器端進(jìn)行,因此不受瀏覽器同源策略的限制。
實(shí)現(xiàn):可以使用Nginx、Node.js等搭建代理服務(wù)器。例如,Nginx可以通過(guò)配置反向代理來(lái)解決跨域問(wèn)題;Node.js可以搭建一個(gè)中間層服務(wù)器,接收客戶端的請(qǐng)求,然后將請(qǐng)求轉(zhuǎn)發(fā)給目標(biāo)服務(wù)器,并將返回的數(shù)據(jù)再轉(zhuǎn)發(fā)給客戶端。
4、前端正向代理
原理:在客戶端設(shè)置一個(gè)代理服務(wù)器,并指定目標(biāo)服務(wù)器。代理服務(wù)器向目標(biāo)服務(wù)器轉(zhuǎn)交請(qǐng)求,并將獲得的內(nèi)容發(fā)送給客戶端。這種方式在客戶端進(jìn)行了請(qǐng)求轉(zhuǎn)發(fā),但同樣實(shí)現(xiàn)了跨域請(qǐng)求。
實(shí)現(xiàn):可以通過(guò)在客戶端代碼中配置代理服務(wù)器地址和端口,以及目標(biāo)服務(wù)器的地址和端口來(lái)實(shí)現(xiàn)。在發(fā)送請(qǐng)求時(shí),將請(qǐng)求地址替換為代理服務(wù)器的地址,并在代理服務(wù)器中進(jìn)行請(qǐng)求轉(zhuǎn)發(fā)。
5、配置瀏覽器插件或工具
有些瀏覽器插件或工具(如Postman、curl等)可以繞過(guò)瀏覽器的同源策略限制,直接發(fā)送跨域請(qǐng)求。但這種方法主要用于開發(fā)和測(cè)試階段,不建議在生產(chǎn)環(huán)境中使用。
補(bǔ)充:關(guān)于Spring Security的CSRF
關(guān)于Spring Security的CSRF
一、CSRF是什么
CSRF(Cross-Site Request Forgery,跨站請(qǐng)求偽造)是一種常見的網(wǎng)絡(luò)攻擊方式,攻擊者通過(guò)偽裝用戶的請(qǐng)求,利用用戶在其他網(wǎng)站上已經(jīng)登錄的身份權(quán)限來(lái)執(zhí)行惡意操作。為了防止 CSRF 攻擊,Spring Security 提供了內(nèi)置的 CSRF 保護(hù)功能。
二、Spring Security中的CSRF保護(hù)
在Spring框架中,如果引入了Spring Security依賴,除了會(huì)默認(rèn)開啟身份驗(yàn)證,同時(shí)還會(huì)開啟CSRF保護(hù)功能。
啟用此功能可確保,在會(huì)更改狀態(tài)的HTTP請(qǐng)求上,如果沒(méi)有帶上有效的X-CSRFToken,則會(huì)出現(xiàn) 403 錯(cuò)誤。
HTTP狀態(tài)碼403表示禁止訪問(wèn),即服務(wù)器理解請(qǐng)求客戶端的請(qǐng)求,但是拒絕執(zhí)行這個(gè)請(qǐng)求。這通常是由于客戶端沒(méi)有足夠的權(quán)限訪問(wèn)該資源所導(dǎo)致的。
可以認(rèn)為安全的方法都是只讀的方法(GET, HEAD, OPTIONS),這些類型的請(qǐng)求不會(huì)改變資源狀態(tài),被認(rèn)為是冪等的,即調(diào)用相同的URL多次得到的結(jié)果不變。
DELETE方法的語(yǔ)義表示刪除服務(wù)器上的一個(gè)資源,第一次刪除成功后該資源就不存在了,資源狀態(tài)改變了,所以DELETE方法不具備安全特性。然而HTTP協(xié)議規(guī)定DELETE方法是冪等的,每次刪除該資源都要返回狀態(tài)碼200 OK,服務(wù)器端要實(shí)現(xiàn)冪等的DELETE方法,必須記錄所有已刪除資源的元數(shù)據(jù)(Metadata),否則,第二次刪除后返回的響應(yīng)碼就會(huì)類似404 Not Found了。
PUT和POST方法語(yǔ)義中都有修改資源狀態(tài)的意思,因此都不是安全的。但是PUT方法是冪等的,POST方法不是冪等的,這么設(shè)計(jì)的理由是:
HTTP協(xié)議規(guī)定,POST方法修改資源狀態(tài)時(shí),URL指示的是該資源的父級(jí)資源,待修改資源的ID信息在請(qǐng)求體中攜帶。而PUT方法修改資源狀態(tài)時(shí),URL直接指示待修改資源。因此,同樣是創(chuàng)建資源,重復(fù)提交POST請(qǐng)求可能產(chǎn)生兩個(gè)不同的資源,而重復(fù)提交PUT請(qǐng)求只會(huì)對(duì)其URL中指定的資源起作用,也就是只會(huì)創(chuàng)建一個(gè)資源。
因此,當(dāng)Spring Security使用默認(rèn)配置,或手動(dòng)開啟CSRF保護(hù)功能時(shí),我們會(huì)發(fā)現(xiàn),GET請(qǐng)求是正常的,但是POST請(qǐng)求會(huì)報(bào)403錯(cuò)誤。
三、處理方法
處理方法一:跳過(guò)安全檢查(不推薦,因?yàn)檫@個(gè)一般是用于靜態(tài)資源等)
@Bean //(Spring Security6.2.4寫法) public WebSecurityCustomizer webSecurityCustomizer() { // 匹配的路徑,直接跳過(guò)安全檢查 return (web) -> web.ignoring().requestMatchers("/static/**"); }
處理方法二:關(guān)閉CSRF保護(hù)功能
@Bean //(Spring Security6.2.4寫法) public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http.authorizeHttpRequests( (authz) -> authz .anyRequest().authenticated()) .httpBasic(withDefaults()) .formLogin(withDefaults()) .csrf((csrf)->csrf.disable()); //只對(duì)匹配路徑關(guān)閉CSRF //.csrf((csrf)->csrf.ignoringRequestMatchers("/路徑")); return http.build(); }
處理方法三:正常在請(qǐng)求時(shí)帶上X-CSRFToken
到此這篇關(guān)于關(guān)于Spring Security的CORS的文章就介紹到這了,更多相關(guān)Spring Security的CORS內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
使用Java把文本內(nèi)容轉(zhuǎn)換成網(wǎng)頁(yè)的實(shí)現(xiàn)方法分享
這篇文章主要介紹了使用Java把文本內(nèi)容轉(zhuǎn)換成網(wǎng)頁(yè)的實(shí)現(xiàn)方法分享,利用到了Java中的文件io包,需要的朋友可以參考下2015-11-11IntelliJ IDEA版Postman強(qiáng)大功能介紹
這篇文章主要為大家介紹了IDEA版Postman的強(qiáng)大功能介紹,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-06-06java虛擬機(jī)運(yùn)行時(shí)數(shù)據(jù)區(qū)分析
這篇文章主要介紹了java虛擬機(jī)運(yùn)行時(shí)數(shù)據(jù)區(qū)分析,具有一定參考價(jià)值,需要的朋友可以了解下。2017-11-11Springboot PostMapping無(wú)法獲取數(shù)據(jù)問(wèn)題及解決
這篇文章主要介紹了Springboot PostMapping無(wú)法獲取數(shù)據(jù)問(wèn)題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-05-05Java中遇到的For?input?string問(wèn)題解決辦法
這篇文章主要給大家介紹了關(guān)于Java中遇到的For?input?string問(wèn)題的解決辦法,如果出現(xiàn)這樣的異常報(bào)錯(cuò),是指的數(shù)據(jù)轉(zhuǎn)換時(shí)出錯(cuò),文中通過(guò)圖文介紹的非常詳細(xì),需要的朋友可以參考下2023-11-11springboot使用GuavaCache做簡(jiǎn)單緩存處理的方法
這篇文章主要介紹了springboot使用GuavaCache做簡(jiǎn)單緩存處理的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-01-01Javaweb開發(fā)中通過(guò)Servlet生成驗(yàn)證碼圖片
這篇文章主要為大家詳細(xì)介紹了Javaweb開發(fā)中通過(guò)Servlet生成驗(yàn)證碼圖片的相關(guān)資料,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-05-05