Azure 儲存體的跨原始來源資源分享 (CORS) 支援

從 2013-08-15 版開始,Azure 儲存體服務支援 Blob、資料表和佇列服務的「跨原始資源共用」(CORS)。 檔案服務支援從 2015-02-21 版開始的 CORS。

CORS 是一項 HTTP 功能,可讓 Web 應用程式在某個網域下執行,以存取其他網域中的資源。 網頁瀏覽器會實作稱為 相同原始原則 的安全性限制,它可防止網頁呼叫不同網域中的 API;CORS 則提供了一個安全的方式,可讓一個網域 (原始網域) 能夠呼叫其他網域中的 API。 如需 CORS 的詳細資訊,請參閱 CORS 規格

您可以呼叫 [設定 Blob 服務屬性]、[ 設定檔案服務屬性]、[ 設定佇列服務屬性] 和 [ 設定資料表服務屬性],個別設定每個 Azure 儲存體服務的 CORS 規則。 一旦設定服務的 CORS 規則之後,將評估從不同網域對服務所提出的適當授權要求,以判斷是否可根據您指定的規則來允許它。

重要事項

CORS 不是授權機制。 啟用 CORS 時,針對儲存體資源提出的任何要求都必須具有有效的授權標頭,或必須針對公用資源提出。

除了進階效能層級中的一般用途 v1 或 v2 儲存體帳戶以外,所有儲存體帳戶類型都支援 CORS。

了解 CORS 要求

來自原始網域的 CORS 要求可能包含兩個不同要求:

  • 預檢要求,其會查詢服務所加諸的 CORS 限制。 除非要求方法是 簡單的方法(意即 GET、HEAD 或 POST),否則必須執行預檢要求。

  • 對所需資源提出的實際要求。

預檢要求

預檢要求會查詢由帳戶擁有者為儲存體服務所建立的 CORS 限制。 Web 瀏覽器 (或其他使用者代理程式) 會傳送包含要求標頭、方法和原始網域的 OPTIONS 要求。 儲存體服務會根據一組預先設定的 CORS 規則來評估預定作業,這些規則會指定需在對儲存體資源提出的實際要求上指定哪些原始網域、要求方法和要求標頭。

如果已啟用服務的 CORS 且 CORS 規則符合預檢要求,服務會以狀態碼 200 (確定) 回應,並在回應中包含必要的存取控制標頭。

如果未啟用服務的 CORS,或是 CORS 規則不符合預檢要求,服務會回應狀態碼 403 (禁止)。

如果 OPTIONS 要求未包含必要的 CORS 標頭 (Origin 和 Access-Control-Request-Method 標頭),服務會回應狀態碼 400 (不正確的要求)。

請注意,預檢要求會根據服務 (Blob、檔案、佇列或資料表) 進行評估,而不是根據要求的資源評估。 帳戶擁有者必須已設定適當的帳戶服務屬性來啟用 CORS,要求才能成功。

實際要求

一旦接受預檢要求並傳回回應之後,瀏覽器便會對儲存體資源發送實際要求。 如果預檢要求遭到拒絕,瀏覽器將立即拒絕實際要求。

實際要求會被視為對儲存體服務提出的一般要求。 Origin 標頭的目前狀態表示要求是 CORS 要求,而服務將檢查 CORS 比對規則。 如果找到相符項目,就會將 Access-Control 標頭加入回應並傳送回用戶端。 如果找不到相符項目,就不會傳回 CORS Access-Control 標頭。

啟用 Azure 儲存體的 CORS

CORS 規則是在服務層級設定,因此您必須針對每個服務分別啟用或停用 CORS (Blob、檔案、佇列和資料表) 。 根據預設,每個服務都會停用 CORS。 若要啟用 CORS,您必須針對 Blob、佇列和資料表服務或 2015-02-21 版或檔案服務使用 2013-08-15 版或更新版本來設定適當的服務屬性。 您可以藉由將 CORS 規則新增至服務屬性來啟用 CORS。 如需如何啟用或停用服務 CORS 以及如何設定 CORS 規則的詳細資訊,請參閱 設定 Blob 服務屬性設定檔案服務屬性設定資料表服務屬性設定佇列服務屬性

以下是透過作業指定的單一 Set Service Properties CORS 規則範例:

<Cors>
    <CorsRule>  
        <AllowedOrigins>http://*.contoso.com, http://www.fabrikam.com</AllowedOrigins>  
        <AllowedMethods>PUT,GET</AllowedMethods>  
        <AllowedHeaders>x-ms-meta-data*,x-ms-meta-target*,x-ms-meta-abc</AllowedHeaders>  
        <ExposedHeaders>x-ms-meta-*</ExposedHeaders>  
        <MaxAgeInSeconds>200</MaxAgeInSeconds>  
    </CorsRule>  
<Cors>  
  

CORS 規則中包含的每個項目敘述如下:

  • AllowedOrigins:允許透過 CORS 對儲存體服務提出要求的原始網域。 原始網域是要求的來源網域。 請注意,原始網域的大小寫必須與使用者代理程式傳送至服務的原始網域完全相符。

    您可以使用萬用字元 '*' 取代指定的網域,以允許所有原始網域透過 CORS 提出要求。 您也可以使用萬用字元取代子域,以允許指定網域的所有子域透過 CORS 提出要求。 在上述範例中,的所有子域 contoso.com 都可以透過 CORS 提出要求,而 只有 來自 www 子域 fabrikam.com 的要求可以透過 CORS 進行。

  • AllowedMethods:原始網域可能用於 CORS 要求的方法 (HTTP 要求動詞命令)。 在上述範例中,只允許 PUT 和 GET 要求。

  • AllowedHeaders:原始網域可在 CORS 要求上指定的要求標頭。 在上述範例中,允許開頭為 x-ms-meta-datax-ms-meta-targetx-ms-meta-abc 的所有中繼資料標頭。 請注意,萬用字元 '*' 表示允許任何以指定前置詞開頭的標頭。

  • ExposedHeaders:對 CORS 要求的回應中可能傳送回應標頭,且瀏覽器可能會向發出要求的人員公開回應標頭。 在上述範例中,系統會指示瀏覽器公開開頭為 x-ms-meta 的所有標頭。

  • MaxAgeInSeconds:瀏覽器應該快取預檢 OPTIONS 要求的最大時間量。

Azure 儲存體服務支援為 AllowedHeadersExposedHeaders 元素指定帶有前置詞的標頭。 若要允許標頭的類別,您可以指定該類別的一般前置詞。 例如,指定 x-ms-meta* 做為帶有前置詞的標頭,以建立比對開頭為 x-ms-meta 之所有標頭的規則。

下列限制適用於 CORS 規則:

  • 每個儲存體服務最多可以指定五個 CORS 規則, (Blob、檔案、資料表和佇列) 。

  • 要求上所有 CORS 規則設定的大小上限,不包括 XML 標籤,不應超過 2 KiB。

  • 允許的標頭、公開的標頭或允許的原始網域的長度不可超過 256 個字元。

  • 允許的標頭和公開的標頭可以是:

    • 常值標頭,此標頭是確切的標頭名稱,例如 x-ms-meta-processed。 最多可在要求上指定 64 個常值標頭。
    • 前置標頭,其中提供標頭的前置詞,例如 x-ms-meta-data*。 以這種方式指定前置詞,可允許或公開以指定前置詞開頭的任何標頭。 最多可在要求上指定兩個有前置詞的標頭。
  • AllowedMethods 元素中指定的方法 (或 HTTP 動詞命令) 必須符合 Azure 儲存體服務 API 所支援的方法。 支援的方法包括 DELETE、GET、HEAD、MERGE、POST、PATCH、OPTIONS 和 PUT。

了解 CORS 規則評估邏輯

當儲存體服務收到預檢或實際要求時,它會透過適當的設定服務屬性作業,根據您已為服務建立的 CORS 規則來評估該要求。 CORS 規則會以設定服務屬性作業的要求主體中所設定的順序進行評估。

CORS 規則的評估,如下所示:

  1. 首先會根據 AllowedOrigins 元素列出的網域來檢查要求的原始網域。 如果清單中包含原始網域,或是使用了萬用字元 '*' 來允許所有網域,則會繼續評估規則。 如果未包含原始網域,則要求會失敗。

  2. 接著會根據 AllowedMethods 元素列出的方法來檢查要求的方法 (或 HTTP 動詞命令)。 如果方法包含於清單中,就會繼續評估規則;如果沒有,則要求會失敗。

  3. 如果要求符合其原始網域及其方法中的規則,就會選取該規則來處理要求,且不會評估任何其他規則。 不過,系統會根據 AllowedHeaders 元素列出的標頭來檢查在要求上指定的所有標頭,在這之後,要求才會成功。 如果傳送的標頭與允許的標頭不符,則要求會失敗。

因為這些規則會依照它們在要求主體中出現的順序來處理,所以,最佳做法建議您先在清單中指定與原始網域有關的最嚴格規則,以便先評估這些規則。 將較不嚴格的規則指定於清單結尾 - 例如,允許所有原始網域的規則。

範例 - CORS 規則評估

下列範例示範作業的部分要求主體,以設定儲存體服務的 CORS 規則。 如需建構要求的詳細資訊,請參閱 設定 Blob 服務屬性設定檔案服務屬性設定佇列服務屬性設定資料表服務屬性

<Cors>  
    <CorsRule>  
        <AllowedOrigins>http://www.contoso.com</AllowedOrigins>  
        <AllowedMethods>PUT,HEAD</AllowedMethods>  
        <MaxAgeInSeconds>5</MaxAgeInSeconds>  
        <ExposedHeaders>x-ms-*</ExposedHeaders>  
        <AllowedHeaders>x-ms-blob-content-type, x-ms-blob-content-disposition</AllowedHeaders>  
    </CorsRule>  
    <CorsRule>  
        <AllowedOrigins>*</AllowedOrigins>  
        <AllowedMethods>PUT,GET</AllowedMethods>  
        <MaxAgeInSeconds>5</MaxAgeInSeconds>  
        <ExposedHeaders>x-ms-*</ExposedHeaders>  
        <AllowedHeaders>x-ms-blob-content-type, x-ms-blob-content-disposition</AllowedHeaders>  
    </CorsRule>  
    <CorsRule>  
        <AllowedOrigins>http://www.contoso.com</AllowedOrigins>  
        <AllowedMethods>GET</AllowedMethods>  
        <MaxAgeInSeconds>5</MaxAgeInSeconds>  
        <ExposedHeaders>x-ms-*</ExposedHeaders>  
        <AllowedHeaders>x-ms-client-request-id</AllowedHeaders>  
    </CorsRule>  
</Cors>

接下來,請考慮下列 CORS 要求:

方法 來源 要求標頭 規則相符 結果
PUT http://www.contoso.com x-ms-blob-content-type 第一個規則 Success
GET http://www.contoso.com x-ms-blob-content-type 第二個規則 Success
GET http://www.contoso.com x-ms-client-request-id 第二個規則 失敗

第一個要求符合第一個規則 (原始網域符合允許的原始網域、方法符合允許的方法,而且標頭符合允許的標頭),因而成功。

第二個要求不符合第一個規則,因為此方法不符合允許的方法。 不過,它與第二個規則相符,因而成功。

第三個要求符合其原始網域和方法中的第二個規則,所以不會進一步評估任何規則。 但是,第二項規則不允許 x-ms-client-request-id 標頭,因此儘管第三項規則的語意事實上允許要求成功,但要求仍失敗。

注意

雖然相較於之前較嚴格的規則,此範例示範的規則已較不嚴格,但一般最佳做法是先列出最嚴格的規則。

了解如何設定 Vary 標頭

Vary 標頭是由一組要求標頭欄位所組成的標準 HTTP/1.1 標頭,這些欄位向瀏覽器或使用者代理程式建議相關準則 (伺服器已選取這些準則來處理要求)。 Vary 標頭主要提供給 Proxy、瀏覽器及 CDN 用於快取,Proxy、瀏覽器及 CDN 使用此標頭來決定回應的快取方式。 如需詳細資訊,請參閱 Vary 標頭的規格。

當瀏覽器或其他使用者代理程式快取來自 CORS 要求的回應時,會將原始網域快取為允許的原始網域。 當第二個網域在快取作用中時發出相同的儲存體資源要求,使用者代理程式便會擷取快取的原始網域。 第二個網域不符合快取的網域,因此要求失敗 (它本來可以成功)。 在某些情況下,當要求網域與快取的來源不同時,Azure 儲存體會將 Vary 標頭設定為 Origin ,以指示使用者代理程式將後續 CORS 要求傳送至服務。

在下列情況下,Azure 儲存體會將 Vary 實際 GET/HEAD 要求的標頭 Origin 設定為 :

  • 當要求的原始網域完全符合 CORS 規則所定義的允許來源。 若要完全符合,CORS 規則不可以包含萬用字元 '*'。

  • 沒有比對要求原始網域的規則,但會啟用儲存體服務的 CORS。

在 GET/HEAD 要求符合允許所有原始網域的 CORS 規則的情況下,回應會指出允許所有原始網域,而且當快取作用中時,使用者代理程式快取將會允許來自任何原始網域的後續要求。

請注意,如果要求使用非 GET/HEAD 方法,儲存體服務不會設定 Vary 標頭,因為使用者代理程式不會快取這些方法的回應。

下表指出 Azure 儲存體如何根據先前所述的案例來回應 GET/HEAD 要求:

要求上存在的 Origin 標頭 針對此服務指定的 CORS 規則 比對規則存在,允許所有來源 (*) 有完全符合原始網域的比對規則存在 回應包含已設為 Origin 的 Vary 標頭 回應包括 Access-Control-Allowed-Origin:「*」 回應包含 Access-Control-Exposed-Headers
No No No No No No No
No No No No No
No Yes No No Yes Yes
No No No No No No
Yes No Yes No Yes
Yes No No No No
Yes Yes No No Yes Yes

CORS 要求的計費方式

如果您已針對帳戶的任何儲存體服務啟用 CORS, (呼叫 [設定 Blob 服務屬性]、[ 設定佇列服務屬性]、[ 設定檔案服務屬性] 或 [ 設定資料表服務屬性 ]) ,就會向您收取成功的預檢要求。 若要降低費用,請考慮將 CORS 規則中的 MaxAgeInSeconds 元素設定為大型值,以便使用者代理程式快取要求。

未成功的預檢要求將不會列入計費。

另請參閱

W3C 跨原始資源共用規格