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 流程 - 簡單請求
簡單請求,須符合以下條件:
- 只能是 HTTP GET, POST or HEAD 方法
- 自訂的 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 後,必須告訴瀏覽器允許的 method和 header 有哪些,因此 Server 的回應必須帶有以下兩個 header:
Access-Control-Allow-Methods: 允許的 HTTP method。 Access-Control-Allow-Headers: 允許的非「簡單」header。
瀏覽器取得伺服器的回應後,如果符合連線權限,就會送出真的 request; 如果發現權限不符,就會出現錯誤訊息而中斷送出。