跨源資源共享 (CORS)

安全地分享跨來源資源

Mariko Kosaka

瀏覽器的同源政策會封鎖從不同來源讀取資源的行為。這項機制可防止惡意網站讀取其他網站的資料,但也會阻止合法使用。

現代網頁應用程式通常會想要從其他來源取得資源,例如從其他網域擷取 JSON 資料,或將其他網站的圖片載入 <canvas> 元素。這些資源可能是任何人都能閱讀的公開資源,但同源政策會阻止使用這些資源。開發人員過去曾使用 JSONP 等解決方法。

跨源資源共享 (CORS) 會以標準化方式修正這個問題。啟用 CORS 後,伺服器就能告知瀏覽器可以使用其他來源。

要求及回應
插圖:用戶端要求和伺服器回應。

瀏覽器和伺服器可以使用超文字傳輸通訊協定 (HTTP) 透過網路交換資料。HTTP 定義了要求者和回應者之間的通訊規則,包括取得資源所需的資訊。

HTTP 標頭會交涉用戶端與伺服器之間的訊息交換作業,並可用來判斷存取權。瀏覽器的要求和伺服器的回應訊息都分為標頭內文

訊息的相關資訊,例如訊息類型或訊息編碼。標頭可以包含以鍵/值組合表示的各種資訊。要求標頭和回應標頭包含不同的資訊。

要求標頭範例

Accept: text/html
Cookie: Version=1

這個標頭等同於表示「我想要在回應中收到 HTML。這裡是我擁有的 Cookie」

回應標頭範例

Content-Encoding: gzip
Cache-Control: no-store

這個標頭等同於表示「這個回應中的資料已使用 gzip 編碼。請不要快取。」

內文

訊息本身。可以是純文字、圖片二進位檔、JSON、HTML 或許多其他格式。

CORS 的運作方式為何?

同源政策會指示瀏覽器封鎖跨來源要求。當您需要來自不同來源的公開資源時,提供資源的伺服器會告知瀏覽器,傳送要求的來源可以存取其資源。瀏覽器會記住這項資訊,並允許跨來源資源共用該資源。

步驟 1:用戶端 (瀏覽器) 要求

瀏覽器發出跨來源要求時,會新增含有目前來源 (配置、主機和通訊埠) 的 Origin 標頭。

步驟 2:伺服器回應

如果伺服器看到這個標頭並想允許存取,就會在回應中加入 Access-Control-Allow-Origin 標頭,指定要求來源,或設為 * 以允許任何來源。

步驟 3:瀏覽器收到回應

當瀏覽器看到含有適當 Access-Control-Allow-Origin 標頭的回應時,就會將回應資料分享給用戶端網站。

透過 CORS 分享憑證

基於隱私權考量,CORS 通常用於匿名要求,在這種情況下,要求者不會被識別。如果您想在使用 CORS 時傳送 Cookie,以便識別傳送者,就必須在要求和回應中加入其他標頭。

要求

credentials: 'include' 新增至擷取選項,如以下範例所示。這包括要求中的 Cookie,如下所示:

fetch('https://example.com', {
  mode: 'cors',
  credentials: 'include'
})

回應

Access-Control-Allow-Origin 必須設為特定來源 (不使用 * 的萬用字元),而且 Access-Control-Allow-Credentials 必須設為 true

HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Credentials: true

針對複雜的 HTTP 呼叫預檢要求

當網頁應用程式提出複雜的 HTTP 要求時,瀏覽器會在要求鏈的開頭加入預檢要求

CORS 規格定義了以下複雜要求

  • 使用 GET、POST 或 HEAD 以外方法的要求。
  • 要求包含 AcceptAccept-LanguageContent-Language 以外的標頭。
  • 要求含有 Content-Type 標頭,但非 application/x-www-form-urlencodedmultipart/form-datatext/plain

瀏覽器會自動建立所有必要的預檢要求,並在實際要求訊息之前傳送要求。預檢要求為 OPTIONS 要求,如下所示:

OPTIONS /data HTTP/1.1
Origin: https://example.com
Access-Control-Request-Method: DELETE

在伺服器端,接收要求的應用程式會回應預檢要求,並提供應用程式從此來源接受的方法相關資訊:

HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Methods: GET, DELETE, HEAD, OPTIONS

伺服器回應也可以包含 Access-Control-Max-Age 標頭,以秒為單位指定快取預檢結果的時間長度。這樣一來,用戶端就能傳送多個複雜要求,而不需要重複執行預檢要求。