你可能不知道的CORS跨域資源共享
什么是CORS?
默認(rèn)情況下,為預(yù)防某些而已行為,瀏覽器的XHR對象只能訪問來源于同一個(gè)域中的資源。但是我們在日常實(shí)際開發(fā)中,常常會(huì)遇到跨域請求的需求,因此就出現(xiàn)了一種跨域請求的方案:CORS(Cross-Origin Resource Sharing)跨域資源共享。
CORS背后的原理是:使用自定的HTTP頭部與服務(wù)器進(jìn)行溝通,從而由服務(wù)器決定響應(yīng)是否成功。
了解下同源策略
- 源(origin)*:就是協(xié)議、域名和端口號;
- 同源: 就是源相同,即協(xié)議、域名和端口完全相同;
- 同源策略:同源策略是瀏覽器的一個(gè)安全功能,不同源的客戶端腳本在沒有明確授權(quán)的情況下,不能讀寫對方資源;
- 同源策略的分類:
- DOM 同源策略:即針對于DOM,禁止對不同源頁面的DOM進(jìn)行操作;如不同域名的 iframe 是限制互相訪問。
- XMLHttpRequest 同源策略:禁止使用 XHR 對象向不同源的服務(wù)器地址發(fā)起 HTTP 請求。
- 不受同源策略限制:
- 頁面中的鏈接,重定向以及表單提交(因?yàn)楸韱翁峤?,?shù)據(jù)提交到action域后,本身頁面就和其沒有關(guān)系了,不會(huì)管請求結(jié)果,后面操作都交給了action里面的域)是不會(huì)受到同源策略限制的。
- 資源的引入不受限制,但是js不能讀寫加載的內(nèi)容:如嵌入到頁面中的<script src="..."></script>,<img>,<link>,<iframe>等
為什么要跨域限制
- 如果沒有 DOM 同源策略:那么就沒有啥xss的研究了,因?yàn)槟愕木W(wǎng)站將不是你的網(wǎng)站,而是大家的,誰都可以寫個(gè)代碼操作你的網(wǎng)站界面
- 如果沒有XMLHttpRequest 同源策略,那么就可以很輕易的進(jìn)行CSRF(跨站請求偽造)攻擊:
- 用戶登錄了自己的網(wǎng)站頁面 a.com,cookie中添加了用戶標(biāo)識。
- 用戶瀏覽了惡意頁面 b.com,執(zhí)行了頁面中的惡意 AJAX 請求代碼。
- b.com 向 a.com發(fā)起 AJAX HTTP 請求,請求會(huì)默認(rèn)把 a.com對應(yīng)cookie也同時(shí)發(fā)送過去。
- a.com從發(fā)送的 cookie 中提取用戶標(biāo)識,驗(yàn)證用戶無誤,response 中返回請求數(shù)據(jù);數(shù)據(jù)就泄露了。而且由于Ajax在后臺執(zhí)行,這一過程用戶是無法感知的。
- (附)有了XMLHttpRequest 同源策略就可以限制CSRF攻擊?別忘了還有不受同源策略的:表單提交和資源引入,(安全問題下期在研究)
跨域決解方案
- JSONP 跨域:借鑒于 script 標(biāo)簽不受瀏覽器同源策略的影響,允許跨域引用資源;因此可以通過動(dòng)態(tài)創(chuàng)建 script 標(biāo)簽,然后利用 src 屬性進(jìn)行跨域;
- 缺點(diǎn):
- 所有網(wǎng)站都可以拿到數(shù)據(jù),存在安全性問題,需要網(wǎng)站雙方商議基礎(chǔ)token的身份驗(yàn)證。
- 只能是GET,不能POST。
- 可能被注入惡意代碼,篡改頁面內(nèi)容,可以采用字符串過濾來規(guī)避此問題。
- 服務(wù)器代理:瀏覽器有跨域限制,但是服務(wù)器不存在跨域問題,所以可以由服務(wù)器請求所要域的資源再返回給客戶端。
- document.domain、window.name 、location.hash:借助于iframe決解DOM同源策略
- postMessage:決解DOM同源策略,新方案
- CORS(跨域資源共享):這里講的重點(diǎn)
CORS(跨域資源共享)
- HTML5 提供的標(biāo)準(zhǔn)跨域解決方案,是一個(gè)由瀏覽器共同遵循的一套控制策略,通過HTTP的Header來進(jìn)行交互;主要通過后端來設(shè)置CORS配置項(xiàng)。
CORS簡單使用
之前說得CORS跨域,嗯嗯,后端設(shè)置Access-Control-Allow-Origin:*|[或具體的域名]就好了;
第一次嘗試:
app.use(async(ctx,next) => {
ctx.set({
"Access-Control-Allow-Origin": "http://localhost:8088"
})
發(fā)現(xiàn)有些請求可以成功,但是有些還是會(huì)報(bào)錯(cuò):

請求被同源策略阻止,預(yù)請求的響應(yīng)沒有通過檢查:http返回的不是ok?
并且發(fā)現(xiàn)發(fā)送的是OPTIONS請求:

發(fā)現(xiàn):CORS規(guī)范將請求分為兩種類型,一種是簡單請求,另外一種是帶預(yù)檢的非簡單請求
簡單請求和非簡單請求
瀏覽器發(fā)送跨域請求判斷方式:
- 瀏覽器在發(fā)送跨域請求的時(shí)候,會(huì)先判斷下是簡單請求還是非簡單請求,如果是簡單請求,就先執(zhí)行服務(wù)端程序,然后瀏覽器才會(huì)判斷是否跨域;
- 而對于非簡單請求,瀏覽器會(huì)在發(fā)送實(shí)際請求之前先發(fā)送一個(gè)OPTIONS的HTTP請求來判斷服務(wù)器是否能接受該跨域請求;如果不能接受的話,瀏覽器會(huì)直接阻止接下來實(shí)際請求的發(fā)生。
什么是簡單請求
1、請求方法是如下之一:
- GET
- HEAD
- POST
2、所有的Header都只包含如下列表中(沒有自定義header):
- Cache-Control
- Content-Language
- Content-Type
- Expires
- Last-Modified
- Pragma
除此之外都是非簡單請求
CORS非簡單請求配置須知
正如上圖報(bào)錯(cuò)顯示,對于非簡單請求,瀏覽器會(huì)先發(fā)送options預(yù)檢,預(yù)檢通過后才會(huì)發(fā)送真是的請求;
發(fā)送options預(yù)檢請求將關(guān)于接下來的真實(shí)請求的信息給服務(wù)器:
Origin:請求的源域信息
Access-Control-Request-Method:接下來的請求類型,如POST、GET等
Access-Control-Request-Headers:接下來的請求中包含的用戶顯式設(shè)置的Header列表
服務(wù)器端收到請求之后,會(huì)根據(jù)附帶的信息來判斷是否允許該跨域請求,通過Header返回信息:
Access-Control-Allow-Origin:允許跨域的Origin列表
Access-Control-Allow-Methods:允許跨域的方法列表
Access-Control-Allow-Headers:允許跨域的Header列表,防止遺漏Header,因此建議沒有特殊需求的情況下設(shè)置為*
Access-Control-Expose-Headers:允許暴露給JavaScript代碼的Header列表
Access-Control-Max-Age:最大的瀏覽器預(yù)檢請求緩存時(shí)間,單位為s
CORS完整配置
koa配置CORS跨域資源共享中間件:
const cors = (origin) => {
return async (ctx, next) => {
ctx.set({
"Access-Control-Allow-Origin": origin, //允許的源
})
// 預(yù)檢請求
if (ctx.request.method == "OPTIONS") {
ctx.set({
'Access-Control-Allow-Methods': 'OPTIONS,HEAD,DELETE,GET,PUT,POST', //支持跨域的方法
'Access-Control-Allow-Headers': '*', //允許的頭
'Access-Control-Max-Age':10000, // 預(yù)檢請求緩存時(shí)間
// 如果服務(wù)器設(shè)置Access-Control-Allow-Credentials為true,那么就不能再設(shè)置Access-Control-Allow-Origin為*,必須用具體的域名
'Access-Control-Allow-Credentials':true // 跨域請求攜帶身份信息(Credential,例如Cookie或者HTTP認(rèn)證信息)
});
ctx.send(null, '預(yù)檢請求')
} else {
// 真實(shí)請求
await next()
}
}
}
export default cors
現(xiàn)在不管是簡單請求還是非簡單請求都可以跨域訪問啦~
跨域時(shí)如何處理cookie
cookie:
- 我們知道http時(shí)無狀態(tài)的,所以在維持用戶狀態(tài)時(shí),我們一般會(huì)使用cookie;
- cookie每次同源請求都會(huì)攜帶;但是跨域時(shí)cookie是不會(huì)進(jìn)行攜帶發(fā)送的;
問題:
- 由于cookie對于不同源是不能進(jìn)行操作的;這就導(dǎo)致,服務(wù)器無法進(jìn)行cookie設(shè)置,瀏覽器也沒法攜帶給服務(wù)器(場景:用戶登錄進(jìn)行登錄操作后,發(fā)現(xiàn)響應(yīng)中有set-cookie但是,瀏覽器cookie并沒有相應(yīng)的cookie)
決解:
- 瀏覽器請求設(shè)置withCredentials為true即可讓該跨域請求攜帶 Cookie;使用axios配置axios.defaults.withCredentials = true
- 服務(wù)器設(shè)置Access-Control-Allow-Credentials=true允許跨域請求攜帶 Cookie
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對腳本之家的支持。
相關(guān)文章
JS數(shù)字抽獎(jiǎng)游戲?qū)崿F(xiàn)方法
這篇文章主要介紹了JS數(shù)字抽獎(jiǎng)游戲?qū)崿F(xiàn)方法,可實(shí)現(xiàn)按下回車鍵出現(xiàn)隨機(jī)數(shù)字切換的效果,涉及時(shí)間與隨機(jī)數(shù)的相關(guān)操作技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2015-05-05
js設(shè)計(jì)模式之代理模式及訂閱發(fā)布模式實(shí)例詳解
這篇文章主要介紹了js設(shè)計(jì)模式之代理模式及訂閱發(fā)布模式,結(jié)合實(shí)例形式詳細(xì)分析了代理模式及訂閱發(fā)布模式的概念、原理、實(shí)現(xiàn)方法及相關(guān)操作注意事項(xiàng),需要的朋友可以參考下2019-08-08
TypeScript裝飾器與反射元數(shù)據(jù)實(shí)例詳解
TypeScript的裝飾器為我們提供了一種強(qiáng)大的工具,可以在運(yùn)行時(shí)改變類的行為,通過理解裝飾器的工作原理,我們可以創(chuàng)造更加強(qiáng)大、靈活且易于維護(hù)的應(yīng)用,這篇文章主要介紹了TypeScript裝飾器與反射元數(shù)據(jù),需要的朋友可以參考下2023-09-09
canvas實(shí)現(xiàn)圖片根據(jù)滑塊放大縮小效果
本文主要介紹了canvas實(shí)現(xiàn)圖片根據(jù)滑塊放大縮小效果的實(shí)例,具有很好的參考價(jià)值,下面跟著小編一起來看下吧2017-02-02
javascript定義變量時(shí)帶var與不帶var的區(qū)別分析
這篇文章主要介紹了javascript定義變量時(shí)帶var與不帶var的區(qū)別,以一個(gè)簡單實(shí)例分析了變量定義時(shí)帶var與不帶var的執(zhí)行原理及用法區(qū)別,需要的朋友可以參考下2015-01-01
JavaScript自動(dòng)設(shè)置IFrame高度的小例子
JavaScript自動(dòng)設(shè)置IFrame高度的小例子,需要的朋友可以參考一下2013-06-06

