CORS跨域請求

NancyJY發表於2019-05-06

何為跨域請求

若請求的url的協議、域名、埠中的任意一個與當前的url不同,即為跨域請求。

跨域請求使得頁面體驗更好,但同時也帶來了安全隱患。常見的一種網路攻擊叫CSRF(Cross-site request forgery)。它的攻擊原理大致如下:

  1. 使用者訪問正常網站A,諸如某銀行,登入進去,A生成cookie資訊並返回給使用者的瀏覽器
  2. 保持網站A的登入狀態,在同一個瀏覽器視窗的新tab頁進入惡意網站B
  3. B網站的惡意程式碼被執行,要求跨域請求A網站的某些資源,諸如轉賬功能
  4. 瀏覽器響應該請求,在使用者不知情的情況下攜帶cookie資訊,向A發出請求
  5. 網站A根據使用者的cookie資訊核實使用者身份,處理該請求,那麼來自網站B的惡意請求被執行

CORS驗證機制

基於CSRF等安全隱患,瀏覽器會限制從指令碼發出的跨域請求,雖然安全性更高,頁面體驗卻差了。於是W3C推出了一種跨域的訪問驗證的機制,即CORS,這種機制支援跨域請求,且跨站資料傳輸更安全。

CORS驗證機制需要客戶端和服務的協同處理。

客戶端處理機制

瀏覽器會對所有跨域請求進行驗證,分為簡單請求驗證處理和預檢請求驗證處理。那麼對應的就有簡單請求和非簡單請求之分。

簡單請求

若一個請求同時滿足以下兩個條件,那麼則為簡單請求。

  • 請求方法為GET或HEAD或POST
  • 請求頭中的Content-Type值為application/x-www-form-urlencoded 或 multipart/form-data 或 text/plain

對於簡單請求,瀏覽器直接傳送該請求,在同一個請求中作跨域驗證。怎麼驗證呢?在請求頭上附上Origin屬性,表明這是一個跨域請求。伺服器接到請求,根據設定的跨域規則來驗證,驗證通過,返回Access-Control-Allow-Origin等以Access-Control-開頭的響應頭以及請求的資源,否則返回403狀態碼,且不會返回請求的資源。

CORS跨域請求

非簡單請求

不為簡單請求的跨域請求均為非簡單請求。

非簡單請求的跨域驗證通過一個預檢請求來驗證,即在傳送一個正式的跨域請求之前,傳送一個預檢請求,用來檢查當前網頁所在的域名是否在伺服器的許可名單中以及可使用哪些請求方法,請求頭欄位。

預檢請求

  • 請求方法為OPTIONS
  • 請求頭欄位包括 Origin, Access-Control-Request-Method(表明正式的跨域請求可能用到的方法),Access-Control-Request-Headers(表明正式的跨域請求可能用到的頭欄位)

若預檢請求通過驗證,則響應欄位裡會包含如下欄位:

Access-Control-Allow-Origin:值為請求頭中的origin值或*

Access-Control-Allow-Methods: 表明可被支援的請求方法

Access-Control-Allow-Headers: 表明可被支援的頭資訊欄位

Access-Control-Allow-Credentials: 當請求要求攜帶證書資訊(例如cookie,授權資訊等)驗證,伺服器端是否允許攜帶

Access-Control-Max-Age: 本次預檢請求的有效期,單位為秒

若預檢請求沒通過驗證,則響應欄位裡不會包含以Access-Control-開頭的響應欄位,且不會傳送正式的跨域請求

CORS跨域請求

正式的跨域請求

與簡單請求一樣,請求頭中附帶Origin

CORS跨域請求

攜帶證書資訊的請求

一般情況下,跨域請求不攜帶證書資訊。但若請求的證書模式(credentials mode)被設為include,那麼表明該請求需要攜帶證書資訊。請求的證書模式可通過xmlHttpRequest.withCredentials = true設定或呼叫fetch([url],{mode:"include"})實現。

在簡單請求及正式的非簡單請求中,請求頭附帶證書資訊,響應頭回應:Access-Control-Allow-Credentials:true,並返回請求資源。

CORS跨域請求

在預檢請求中,請求頭並不會附帶證書,響應頭會回應:Access-Control-Allow-Credentials:true。

CORS跨域請求

有一點需注意:若伺服器端同意請求攜帶資訊,則Access-Control-Allow-Origin不能為*,只能為請求頭中指定的Origin值。

伺服器端機制

  1. 檢查http頭部是否有Origin欄位
  2. 沒有或不允許,則當作普通請求處理,結束
  3. 若有且允許跨源,再看是否是預檢請求(method為OPTIONS)
  4. 是預檢請求,返回Access-Control-Allow-Origin,Access-Control-Allow-Methods等資訊,內容為空
  5. 不是預檢請求,返回Access-Control-Allow-Origin,Access-Control-Allow-Credentials等資訊,內容為請求的資源。



相關文章