Skip to main content

[CORS] 1. CORS 是什麼? 為什麼要有 CORS ?

什麼是 CORS?

先來說明一下什麼是 Origin

Origin: 由 protocol + host + port,ex:

- https://www.benson-chen.com
- http://www.mecha-chen.com:80
- https://www.hello-world.com:443

如果 fetch, XMLHTTPRequest 的 api origin 不一樣,就會被 Cross Origin Resource Sharing (CORS) policy 阻擋


script, img 的 src 不在此限制

因為像 script, img 的 src 只是取得資源,對 Server 沒有什麼安全上的疑慮,所以沒有在 CORS policy 的限制範圍裡



為什麼要有 CORS?

簡單來說,就是

info

你是從其他家 domain 來的,要跟我家 domain 的 Server 互動是有些規範的


沒有 CORS 的話,駭客就可以在任意網站去跟你的 Server 做互動了



陷阱: Server 其實還是會處理 request

雖說有了 CORS 之後,駭客不能隨意跟 Server 互動,但是阻擋的方式只是


caution

Browser 不把 "已經取得 respones 的結果" 回傳給你看


驚不驚喜,意不意外 😈😈😈




怎麼說呢? 你會看見的錯誤訊息如下:

CORS error

request has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource


有沒有發現亮點? Access-Control-Allow-Origin 是 Server 的 response 才會加上的 header,表示 Server 其實已經處理完 request 了

那如果我們的 request 其實會去更改 DB 的資料,像是 PUT /user/:id 或是 DELETE /user/:id 呢?

那這時候就悲劇了,就算有 CORS 的保護,Server 的 DB 資料還是會被砍掉,所以呢? 又有另外一個機制幫我們去區分 request,來針對不同安全程度的 request 做不同的處理,分別是 簡單請求 & 一般請求,我們接下來就會針對這 2 種請求來做說明



簡單請求

在只符合特定簡單內容的條件下,因為安全性疑慮比較低,會直接對 Server 發送請求


請求內容

  • Method: GET, POST, HEAD
  • Request header:
    • Accept
    • Accept Language
    • Content-Language
    • Content-Type: application/x-www-form-urlencoded, multipart/form-data, text/plain

一般請求

如果不符合上述簡單請求的條件,會對 Server 先發送 Preflight request ,再發送一般 request

Preflight Request (預檢請求)

會先對 Server 發送預檢請求,表示有哪一些 HTTP method 的 options,故發送的 request 為 HTTP OPTION method,範例如下

OPTIONS /data/
Host: othersite.com
Origin: https://shubo.io
Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-MY-CUSTOM-HEADER, Content-Type


為什麼是叫 OPTIONS 呢? 而不是 CHECK 之類的?

HTTP 方法的命名通常與其功能和目的有關。對於 "OPTIONS" 這個名稱,其背後的原因可以從兩個方面來理解:

  1. 提供選項(Options):OPTIONS 方法的主要目的是提供關於目標資源可用的通信選項。換句話說,它告訴客戶端可以對特定資源進行哪些操作,這些操作就是客戶端的“選項”。所以,從這個角度來看,“OPTIONS”這個名稱反映了這個方法的核心功能,即提供有關資源的可用方法和限制的信息


example: js POST fetch

fetch('https://othersite.com/data/', {
method: 'POST',
headers: {
'Content-Type': 'application/json', // 非簡單請求
'X-CUSTOM-HEADER': '123'
}
})

Preflight request

傳送

  • OPTIONS method: 跟 Server 說我想要確認哪些 method 在此 domain 下可以用
  • Host: Client 的 host
  • Origin: Client 的 domain
  • Access-Control-Request-Method: Client 要允許的 method
  • Access-Control-Request-Headers: Client 要允許的 headers
```plaintext
OPTIONS /data/
Host: othersite.com
Origin: https://shubo.io
Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-MY-CUSTOM-HEADER, Content-Type

Preflight response

  • Access-Control-Allow-Methods: Server 允許的 HTTP 方法。
  • Access-Control-Allow-Headers: Server 允許的非「簡單」header。
Access-Control-Allow-Methods: POST
Access-Control-Allow-Headers: X-MY-CUSTOM-HEADER, Content-Type

一般 Request & Response

request:

POST /data/
Host: othersite.com
Origin: https://shubo.io
Content-Type: application/json
X-MY-CUSTOM-HEADER: 123

response:

Access-Control-Allow-Origin: https://shubo.io


結論

  1. 有了 CORS,就可以阻擋 CSRF,避免 hacker 使用 client cookie 取得 client 相關資訊或更改 client 相關資訊
  2. 即便有了 CORS,還是會跟 Server 請求成功,只是簡單請求的話,response 會被 browser 阻擋,一般 request 的話,如果 preflight response fail 了,才會阻擋接下來的請求



參考資源