CORS了解跨來源資源共享

Fri, Jul 17, 2020 1-minute read

前言

在做 Chrome Extension 的登入登出的時候,遇到了所謂的 CORS 的問題,當時並沒有了解它本身,只是想盡辦法讓資料成功打到 Server 端並回傳一個資料給 Extension 儲存下來,結束之後決定來深入了解 CORS 是什麼。

了解 CORS 之前先來了解所謂的 同源政策 (Same Origin Policy)

SOP 是由所有瀏覽器實施的安全措施,它不允許從一個來源加載的腳本和資源與另一個來源進行交互。

這是對於 JavaScript 的一個限制。

舉個例子:

你的網站是 http://www.example.com,你無法向 http://www.test.com 發出XHR requests

那為什麼不行就要先了解網域的格式

舉個範例網址:

http://www.example.com/index.html

http/https 是協定、 example.com 是域名、通訊埠( port )通常 http 預設的 port 是80

只要"不同協定"或"域名"或者是"port"都會被認定不同源

http://www.example.com/background.html 認定同源,原因是檔案路徑不影響

https://www.example.com/index.html 認定不同源,原因是不同協定

http://example.com/index.html 認定不同源,原因是不同域名

http://example.com:81/index.html 認定不同源,原因是不同port

了解完 SOP 就來看看什麼是 CORS 。

CORS(跨來源資源共享)

CORS 出現的意義就是為了繞過 SOP , Origin 是 Server 端的網域名單,只要名單內沒有這串網域就會被 SOP 擋住, Server 端也能限制名單內網域用哪些方法例如:

get 或 post

所說的方法有 get

post

options

說了這麼多我們來舉個例子來更了解狀況:

有一天你用 Facebook 點了一個惡意網站,這網站會向 Facebook 提出請求要取你的個人資料, Facebook 發現這位客人不認識而被 SOP 給擋住。

但是 SOP 也僅僅只是對瀏覽器的限制並不會對 Server 禁止訪問, Server 可以進行 cURL 來發出請求或者是 Postman

CORS 請求方式

但是 CORS 有兩種請求方式 simple requests (簡單請求) 和 preflight requests (預檢請求) ,來分析簡單請求和預檢請求差在哪裡

先來討論簡單請求,簡單請求只要符合以下所有條件就是簡單請求:

打 API 的 method 只要是 get 、 post 或 HEAD

Content-Type header:

application/x-www-form-urlencoded multipart/form-data text/plain 這兩個就可以構成大多數的簡單請求的用例,但想知道詳細列表可以到 MDN

預檢請求:

不滿足於簡單請求的條件就是預檢請求,最常看到不滿足條件的要求是:

Cotent-Type: application/json 預檢會以 HTTP 的 options 發出請求到 Server,確認 API 內容是否安全並送出,由於跨站請求可能會攜帶使用者資料 例如: cookie

遇到 CORS 問題,並怎麼操作?

以 Ruby on Rails 為例子:

有個 rake-cors gem Rails 裡來輕鬆操作 CORS 設定

#config/application.rb
config.middleware.insert_before 0, Rack::Cors do
  allow do
    origins /\Aexample.com\z/ #這就是所說的名單
    resource '/api/v1/', headers: :any, methods: [:get, :post, :options] #限制客人這三個方法能用哪幾個來拜訪我的網站
  end
end

結論

我們在過程知道了什麼是 SOP 和 CORS ,也知道瀏覽器針對不同的 header 針對 CORS 處理 API 的不同方式,最後也研究了對 Server 端怎麼操作 CORS 解決跨來源請求的錯誤。

參考資料

輕鬆理解 Ajax 與跨來源請求

跨來源資源共用 CORS