安全共用跨來源資源
瀏覽器的相同來源政策會禁止讀取不同來源的資源。這項機制可阻止惡意網站讀取其他網站的資料,但也會阻止合法使用。
現代化的網頁應用程式通常會想要從不同的來源取得資源,例如從其他網域擷取 JSON 資料,或是將其他網站的圖片載入 <canvas>
元素中。這些是開放所有人讀取的公開資源,但相同來源政策會封鎖其使用情形。開發人員以往用過 JSONP 等解決方法。
跨源資源共享 (CORS) 會以標準化方式修正這項問題。啟用 CORS 後,伺服器就會通知瀏覽器可以使用其他來源。
資源要求在網路上的運作方式為何?
瀏覽器和伺服器可以使用超文字傳輸通訊協定 (HTTP) 透過網路交換資料。HTTP 會定義要求者與回應者之間的通訊規則,包括取得資源所需的資訊。
HTTP 標頭會交涉用戶端與伺服器之間的訊息交換,並用來決定存取權。瀏覽器的要求和伺服器的回應訊息都會區分為「標頭」和「內文」。
標題
訊息的相關資訊,例如訊息類型或訊息的編碼。標頭可以包含以鍵/值組合表示的多種資訊。要求標頭和回應標頭包含不同的資訊。
要求標頭範例
Accept: text/html
Cookie: Version=1
此標頭的作用相當於「我想接收 HTML 回應。這就是我買的 Cookie」
回應標頭範例
Content-Encoding: gzip
Cache-Control: no-store
此標頭相當於「這個回應中的資料是以 gzip 編碼。請不要快取這個內容。」
Body
訊息本身。這可以是純文字、圖片二進位檔、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
以外標頭的要求。 - 要求含有
application/x-www-form-urlencoded
、multipart/form-data
或text/plain
以外的Content-Type
標頭。
瀏覽器會自動建立所有必要的預檢要求,並在實際要求訊息之前傳送要求。預檢要求是 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
標頭,指定快取預檢結果的持續時間 (以秒為單位)。這可讓用戶端傳送多個複雜的要求,而無需重複發出預檢要求。