CORS 是什么?
跨域資源共享
是一種機(jī)制怯伊,它使用額外的頭
來告訴瀏覽器 讓運(yùn)行在一個(gè) origin (domain) 上的Web應(yīng)用被準(zhǔn)許訪問
來自不同源服務(wù)器
上的指定的資源。當(dāng)一個(gè)資源從與該資源本身所在的服務(wù)器不同的域、協(xié)議或端口請求一個(gè)資源時(shí)簇爆,資源會(huì)發(fā)起一個(gè)跨域 HTTP 請求。
什么情況下需要使用CORS爽撒?
- XMLHttpRequest 和 fetch 請求
- WebGL
- Web字體
- 使用 drawImg 將 image/video 繪制到 canvas 上
- 樣式表
CORS 請求的規(guī)范
當(dāng)瀏覽器檢測到某個(gè)請求跨域之后入蛆, 就會(huì)根據(jù)請求的類型發(fā)送CORS規(guī)定的網(wǎng)絡(luò)請求。具體是指硕勿,簡單請求和非簡單請求具有差異性哨毁。
對于簡單請求, 只要服務(wù)端允許跨域源武, 具體是設(shè)置了Access-Control-Allow-Origin
字段為*
扼褪。這樣會(huì)帶來安全問題想幻, 后面會(huì)繼續(xù)討論。
對于非簡單請求话浇, 一般都會(huì)對服務(wù)器的數(shù)據(jù)進(jìn)行一些操作脏毯, 所以會(huì)首先發(fā)起預(yù)檢請求,詢問服務(wù)器是否允許這次的訪問幔崖。如果允許食店, 在發(fā)起正常的網(wǎng)絡(luò)請求。
預(yù)檢請求
使用HTTP1.1的OPTIONS方法發(fā)起預(yù)檢請求赏寇, 這個(gè)請求用于向服務(wù)端獲取更多的信息吉嫩, 但是不會(huì)對服務(wù)器的資源造成影響。
預(yù)檢請求會(huì)攜帶一下兩個(gè)字段:
Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-PINGOTHER, Content-Type
首部字段 Access-Control-Request-Method
告知服務(wù)器嗅定,實(shí)際請求將使用 POST
方法自娩。首部字段Access-Control-Request-Headers
告知服務(wù)器,實(shí)際請求將攜帶兩個(gè)自定義請求首部字段:X-PINGOTHER
與 Content-Type
露戒。服務(wù)器據(jù)此決定椒功,該實(shí)際請求是否被允許。
預(yù)檢請求的響應(yīng)
瀏覽器發(fā)起預(yù)檢請求之后智什,服務(wù)器發(fā)送回響應(yīng)动漾。響應(yīng)攜帶如下重要字段:
Access-Control-Allow-Origin: http://foo.example
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
Access-Control-Max-Age: 86400
Access-Control-Allow-Methods
: 表示允許請求的方法有POST, GET, OPTIONS
Access-Control-Allow-Headers
: 請求允許的頭部信息類型為: X-PINGOTHER, Content-Type
, 逗號(hào)分割列表。
Access-Control-Max-Age
: 此次預(yù)檢請求的有效期荠锭, 86400秒旱眯, 在有效期內(nèi), 發(fā)送相同請求不需要再發(fā)送預(yù)檢請求证九,如果超過這個(gè)時(shí)間删豺, 對于同一個(gè)請求, 需要再次發(fā)起預(yù)檢請求愧怜。
HTTP 首部響應(yīng)字段
Access-Control-Allow-Origin: <origin>
: origin
參數(shù)的值指定了允許訪問該資源的外域 URI呀页。對于不需要攜帶身份憑證的請求,服務(wù)器可以指定該字段的值為通配符(*)
拥坛,表示允許來自所有域的請求蓬蝶。
Access-Control-Max-Age: <delta-seconds>
: 指定一次預(yù)檢請求的有效期。有效期內(nèi)不會(huì)再次發(fā)送預(yù)檢請求猜惋。
Access-Control-Allow-Methods: <method>[, <method>]*
: 允許請求的方法(get丸氛, post ...)
Access-Control-Expose-Headers: X-My-Custom-Header, X-Another-Custom-Header
: 服務(wù)器把允許瀏覽器訪問的頭放入白名單.
在跨域訪問時(shí),XMLHttpRequest對象的getResponseHeader()方法只能拿到一些最基本的響應(yīng)頭著摔,Cache-Control缓窜、Content-Language、Content-Type、Expires禾锤、Last-Modified私股、Pragma,如果要訪問其他頭恩掷,則需要服務(wù)器設(shè)置本響應(yīng)頭庇茫。
Access-Control-Allow-Headers: <field-name>[, <field-name>]*
: 預(yù)檢響應(yīng)告知瀏覽器允許的實(shí)際請求頭類型。
CORS withCredentials 屬性
CORS請求默認(rèn)不發(fā)送Cookie和HTTP認(rèn)證信息螃成。如果要把Cookie發(fā)到服務(wù)器旦签,一方面要服務(wù)器同意, 另一方面寸宏,開發(fā)者必須在AJAX請求中打開withCredentials屬性宁炫。
server:
Access-Control-Allow-Credentials: true
developer:
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
二者缺一不可。
需要注意的是氮凝,如果要發(fā)送Cookie羔巢,Access-Control-Allow-Origin就不能設(shè)為星號(hào),必須指定明確的罩阵、與請求網(wǎng)頁一致的域名竿秆。同時(shí),Cookie依然遵循同源政策稿壁,只有用服務(wù)器域名設(shè)置的Cookie才會(huì)上傳幽钢,其他域名的Cookie并不會(huì)上傳,且(跨源)原網(wǎng)頁代碼中的document.cookie也無法讀取服務(wù)器域名下的Cookie傅是。
HTTP 首部請求字段
Origin: <origin>
: 表示請求的源匪燕, origin 參數(shù)的值為源站 URI。它不包含任何路徑信息喧笔,只是服務(wù)器名稱帽驯。不管是否為跨域請求,ORIGIN 字段總是被發(fā)送书闸。
Access-Control-Request-Method: <method>
: 將實(shí)際請求所使用的 HTTP 方法告訴服務(wù)器尼变。
Access-Control-Request-Headers: <field-name>[, <field-name>]*
: 將實(shí)際請求所攜帶的首部字段告訴服務(wù)器。
以上浆劲, 來自MDN嫌术。
瀏覽器阻止跨域的兩種方式
- 請求正常發(fā)起, 但是返回的數(shù)據(jù)被瀏覽器攔截
- 請求發(fā)起的時(shí)候被瀏覽器攔截
CORS 的隱患
CSRF(Cross-site request forgery)跨站請求偽造
利用可跨域這一特性梳侨。