安全地分享跨源資源
瀏覽器的同源政策會禁止讀取不同來源的資源。這項機制可防止惡意網站讀取其他網站的資料, 但也會阻礙正當用途。
新式網頁應用程式通常會想從不同來源取得資源,例如從其他網域擷取 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 以外的方法。
- 要求包含
Accept、Accept-Language或Content-Language以外的標頭。 - 要求具有
Content-Type標頭,但不是application/x-www-form-urlencoded、multipart/form-data或text/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 標頭,指定快取預檢結果的時間長度 (以秒為單位)。這項功能可讓用戶端傳送多個複雜要求,不必重複傳送預檢要求。