Kurt/跨域那件事(CORS)

Created Thu, 24 Feb 2022 20:48:42 +0800 Modified Wed, 02 Nov 2022 05:33:26 +0000
1047 Words 5 min

Internet - 跨來源資源共用(CORS)

同源策略(Same-Origin Policy)

瀏覽器允許我們去請求另一個網頁的資源,但僅限相同協定(scheme)、網域(domain)、主機(host)、阜號(port),例如 https://aaa.com 只能存取自己網站裡的資源 (圖片、影片、程式碼等),不允許網站 https://bbb.com 來存取。

此策略是為了防止惡意腳本去取得網頁上的敏感資訊,因為網站很常使用 cookie 之類的來儲存一些使用者的狀態資訊,如果沒有一些保護機制,這些敏感資訊很容易就會被竊取。

注意: 此策略通常只用於使用 JS 等程式去做請求的動作,若是嵌入在 html 的圖片、css.. 等資源是不受此策略限制的,所以跨站請求偽造(CSRF)就是利用這點去做攻擊的

判斷是否同源:

https://aaa.com/page1 & https://aaa.com/page2

https://aaa.com/page1 & http://aaa.com/page2 -> 一個是 http,一個是 https

http://aaa.com/page1 & http://aaa.com:8080/page1 -> Port 不同(前者默認 80)

https://aaa.com/page1 & https://www.aaa.com -> Domain 不同

跨來源資源共用(Cross-Origin Resource Sharing, CORS)

有了同源策略的概念之後,再來就要講到 CORS 的部份,不管是做大專案還是小專案,我們都有很高的機率會遇到需要跨來源請求,例如我們可能為了效能,把不同的資源放在不同的網域,這時你就需要透過 CORS 的規範去取得資源。

跨來源請求分成兩種: 簡單請求非簡單請求

CORS 流程 - 簡單請求

簡單請求,須符合以下條件:

  1. 只能是 HTTP GET, POST or HEAD 方法
  2. 自訂的 request header 只能是 Accept、Accept-Language、Content-Language 或 Content-Type(只能是 application/x-www-form-urlencoded、multipart/form-data 或 text/plain)

若不符合以上任一條件的請求就是非簡單請求。(詳細請看CORS)

舉例來說,下面這個請求不是簡單請求:


const res = await fetch('https://aaa.com/page1', {
  method: 'PUT',
  headers: {
    'Content-Type': 'application/json',
    'My-Header': 'test'
  }
});

不是的點如下:

  • Method 是 PUT
  • Content-Type 是 application/json
  • My-Header 此標頭並不再規範內

如果是一個簡單請求,則直接送出 request。

CORS 流程 - 非簡單請求

如果是一個非簡單請求的 request,會進行 CORS preflight,先對伺服器送 OPTION method 的 preflight request,此 request 會帶有一些特別的 header: Access-Control-Request-Method 告訴伺服器真正的 request 是何種 method、Access-Control-Request-Headers 告訴伺服器我請求的標頭有哪些,範例如下:

OPTIONS /doc HTTP/1.1
Host: bar.other
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:71.0) Gecko/20100101 Firefox/71.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Connection: keep-alive
Origin: https://aaa.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-CUSTOM-HEADER, Content-Type

Server 收到 preflight request 後,必須告訴瀏覽器允許的 methodheader 有哪些,因此 Server 的回應必須帶有以下兩個 header:

Access-Control-Allow-Methods: 允許的 HTTP method。 Access-Control-Allow-Headers: 允許的非「簡單」header。

瀏覽器取得伺服器的回應後,如果符合連線權限,就會送出真的 request; 如果發現權限不符,就會出現錯誤訊息而中斷送出。