IIS CORS 模組組態參考

由 IIS 小組

本文提供 IIS CORS 模組的概觀,並說明模組的設定。

功能概觀

Microsoft IIS CORS 模組是一個延伸模組,可讓網站支援 CORS (跨原始來源資源分享) 通訊協定。

IIS CORS 模組提供一種方式,讓網頁伺服器管理員和網站作者能夠讓其應用程式支援 CORS 通訊協定。 透過本課程模組,開發人員可以將 CORS 邏輯移出其應用程式,並依賴網頁伺服器。 模組的 CORS 要求處理是由組態中定義的規則所決定。 這些 CORS 規則可以輕鬆地定義或設定,以便輕鬆地將所有 CORS 通訊協定處理委派給模組。

IIS CORS 模組是伺服器端 CORS 元件

CORS 通訊協定會控管用戶端/伺服器通訊。 通常,網頁瀏覽器會作為用戶端 CORS 元件,而 IIS 伺服器會以 IIS CORS 模組的協助作為伺服器端 CORS 元件。

CORS 要求會在通訊協定感知用戶端,例如網頁瀏覽器時,對網域提出要求, (來源) 與目前網域不同。 此案例稱為跨原始來源要求。 未使用 CORS 時,用戶端將會封鎖跨原始來源要求。 使用 CORS 模組時,IIS 會通知用戶端是否可以根據 IIS 組態執行跨原始來源要求。

CORS 預檢要求

CORS 預檢要求是用來判斷所要求的資源是否設定為在伺服器跨來源共用。 CORS 預檢使用 HTTP OPTIONS 方法搭配 ACCESS-CONTROL-REQUEST-METHODORIGIN 要求標頭。 IIS CORS 模組的設計目的是在其他 IIS 模組處理相同的要求之前,先處理 CORS 預檢要求。 OPTIONS 要求一律為匿名,因此 CORS 模組會提供 IIS 伺服器正確回應預檢要求的方法,即使需要停用匿名驗證服務器也一樣。

CORS 組態

IIS CORS 是透過網站或應用程式web.config檔案來設定,並在 內 system.webServer 有自己的 cors 組態區段。

以下是為名為 contentSite 的網站啟用 CORS 的設定範例。 * 原點允許所有主機來源;不過,稍後會排除開頭為 http://* 的那些。 https://*.microsoft.com針對主機來源,CORS 回應會以各種 CORS 組態自訂為範例。

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <cors enabled="true" failUnlistedOrigins="true">
            <add origin="*" />
            <add origin="https://*.microsoft.com"
                 allowCredentials="true"
                 maxAge="120"> 
                <allowHeaders allowAllRequestedHeaders="true">
                    <add header="header1" />
                    <add header="header2" />
                </allowHeaders>
                <allowMethods>
                     <add method="DELETE" />
                </allowMethods>
                <exposeHeaders>
                    <add header="header1" />
                    <add header="header2" />
                </exposeHeaders>
            </add>
            <add origin="http://*" allowed="false" />
        </cors>
    </system.webServer>
</configuration>

使用 IIS CORS 模組,您可以:

  1. 啟用、停用整個 IIS 伺服器的 CORS 或特定 IIS 月臺、應用程式、虛擬目錄、實體目錄或 system.webServer/cors (檔案) 。
  2. 將所有原始主機網域設定為以 * 原始主機規則接受。
  3. 設定特定原始主機網域的清單,並只允許具有與其中一個所列原始主機網域相同之原始要求標頭值的 CORS 要求。
  4. 設定原始網域清單時,請設定萬用字元原始主機網域,例如 http://*https://*.mydomain.com
  5. 設定應不允許作為 CORS 要求的原始網域清單。
  6. 使用設定的值自訂 CORS 回應標頭值。

cors 元素的屬性

Attribute 說明
enabled 選擇性的 Boolean 屬性。
指定是否啟用 CORS。
預設值是 false
failUnlistedOrigins 選擇性的 Boolean 屬性。
指定如果要求的原點不符合所設定的來源清單,或原始主機設定為不允許,則指定要設定為 403 的 CORS 回應狀態碼。
預設值是 false

新增原始規則 < 新增>

原始規則

<add>集合的 <cors> 元素會指定要新增至原始規則清單的個別原始來源。

原始規則的屬性

Attribute 說明
origin 必要的字串屬性。
指定要對其強制執行原始規則的來源主機。 您可以使用星號 (*) 將此規則套用至所有原始要求標頭值。 您也可以使用星號 (*) 作為子功能變數名稱稱的萬用字元。 如果有多個原始規則,則不論允許的屬性值為何,都會套用至最特定的原始主機名稱規則。
allowed 選擇性的 Boolean 屬性。
指定是否接受原始主機的 CORS 要求。
預設值是 true
allowCredentials 選擇性的 Boolean 屬性。
指定是否要設定 Access-Control-Allow-Credentials: true CORS 回應標頭。 這個屬性應該只用于特定原始主機名稱,而不是 * 原始主機,以符合 CORS 通訊協定規範。
預設值是 false
maxAge 選擇性的整數屬性。 以秒為單位的持續時間。
指定預檢 CORS 要求的回應標頭值 Access-Control-Max-Age 。 Access-Control-Max-Age 回應標頭應該只針對 CORS 預檢要求設定。 如果您不想在 CORS 回應中設定 Access-Control-Max-Age 標頭,請設定此屬性的 -1。
預設值是 -1

僅使用 * 原始主機規則

如果只有 * 原始主機規則,則 IIS CORS 模組與有特定原始主機名稱規則時有一些不同的行為。 如果只有 * 原始主機規則,IIS CORS 模組會執行下列動作:

  1. 不論用戶端 CORS 元件所傳送的要求標頭值為何,Access-Control-Allow-Origin 回應標頭的值 origin 都會設定為 * 。
  2. 不同: origin 未新增回應標頭,因為 IIS CORS 不會產生 * 以外的 Access-Control-Allow-Origin 回應標頭值,而且不需要使用 Vary: origin 回應標頭值。

原始主機規則的子項目

Element 說明
allowHeaders 會設定allowHeaders集合,用於原始主機規則中所指定原始主機之 CORS 回應標頭的值 Access-Control-Allow-Headers
Access-Control-Allow-Headers回應標頭只會針對實際的 CORS 要求設定,而不是預檢要求。
allowMethods 會設定allowMethods集合,用於原始主機規則中所指定原始主機的 CORS 回應標頭值 Access-Control-Allow-Methods
回應 Access-Control-Allow-Methods 標頭只會針對 CORS 預檢要求設定。
exposeHeaders 會設定publicHeaders集合,用於原始主機規則中所指定原始主機的 CORS 回應標頭值 Access-Control-Expose-Headers
Access-Control-Expose-Headers回應標頭只會針對實際的 CORS 要求設定,而不是預檢要求。

allowHeaders 元素的屬性

Attribute 說明
allowAllRequestedHeaders 選擇性的 Boolean 屬性。 如果這是 true,IIS 模組會採用指定 Access-Control-Request-Headers CORS 要求標頭的值,並使用相同的值設定 Access-Control-Allow-Headers 回應標頭,這表示允許所有指定的標頭。 如果這是 false,它會使用 allowHeaders 集合的標頭值來設定 Access-Control-Allow-Headers 回應標頭,這表示只允許列出的標頭。 預設值是 false

範例程式碼

C#

using System;
using System.Text;
using Microsoft.Web.Administration;

internal static class Sample {

    private static void Main() {

        using(ServerManager serverManager = new ServerManager()) {
            Configuration config = serverManager.GetWebConfiguration("contentSite");

            ConfigurationSection corsSection = config.GetSection("system.webServer/cors");
            corsSection["enabled"] = true;
            corsSection["failUnlistedOrigins"] = true;

            ConfigurationElementCollection corsCollection = corsSection.GetCollection();

            ConfigurationElement addElement = corsCollection.CreateElement("add");
            addElement["origin"] = @"*";
            corsCollection.Add(addElement);

            ConfigurationElement addElement1 = corsCollection.CreateElement("add");
            addElement1["origin"] = @"https://*.microsoft.com";
            addElement1["allowCredentials"] = true;
            addElement1["maxAge"] = 120;

            ConfigurationElement allowHeadersElement = addElement1.GetChildElement("allowHeaders");
            allowHeadersElement["allowAllRequestedHeaders"] = true;

            ConfigurationElementCollection allowHeadersCollection = allowHeadersElement.GetCollection();

            ConfigurationElement addElement2 = allowHeadersCollection.CreateElement("add");
            addElement2["header"] = @"header1";
            allowHeadersCollection.Add(addElement2);

            ConfigurationElement addElement3 = allowHeadersCollection.CreateElement("add");
            addElement3["header"] = @"header2";
            allowHeadersCollection.Add(addElement3);

            ConfigurationElementCollection allowMethodsCollection = addElement1.GetCollection("allowMethods");

            ConfigurationElement addElement4 = allowMethodsCollection.CreateElement("add");
            addElement4["method"] = @"DELETE";
            allowMethodsCollection.Add(addElement4);

            ConfigurationElementCollection exposeHeadersCollection = addElement1.GetCollection("exposeHeaders");

            ConfigurationElement addElement5 = exposeHeadersCollection.CreateElement("add");
            addElement5["header"] = @"header1";
            exposeHeadersCollection.Add(addElement5);

            ConfigurationElement addElement6 = exposeHeadersCollection.CreateElement("add");
            addElement6["header"] = @"header2";
            exposeHeadersCollection.Add(addElement6);
            corsCollection.Add(addElement1);

            ConfigurationElement addElement7 = corsCollection.CreateElement("add");
            addElement7["origin"] = @"http://*";
            addElement7["allowed"] = false;
            corsCollection.Add(addElement7);

            serverManager.CommitChanges();
        }
    }
}

JavaScript


var adminManager = new ActiveXObject('Microsoft.ApplicationHost.WritableAdminManager');
adminManager.CommitPath = "MACHINE/WEBROOT/APPHOST/contentSite";

var corsSection = adminManager.GetAdminSection("system.webServer/cors", "MACHINE/WEBROOT/APPHOST/contentSite");
corsSection.Properties.Item("enabled").Value = true;
corsSection.Properties.Item("failUnlistedOrigins").Value = true;

var corsCollection = corsSection.Collection;

var addElement = corsCollection.CreateNewElement("add");
addElement.Properties.Item("origin").Value = "*";
corsCollection.AddElement(addElement);


var addElement1 = corsCollection.CreateNewElement("add");
addElement1.Properties.Item("origin").Value = "https://*.microsoft.com";
addElement1.Properties.Item("allowCredentials").Value = true;
addElement1.Properties.Item("maxAge").Value = 120;
var allowHeadersElement = addElement1.ChildElements.Item("allowHeaders");
allowHeadersElement.Properties.Item("allowAllRequestedHeaders").Value = true;

var allowHeadersCollection = allowHeadersElement.Collection;

var addElement2 = allowHeadersCollection.CreateNewElement("add");
addElement2.Properties.Item("header").Value = "header1";
allowHeadersCollection.AddElement(addElement2);


var addElement3 = allowHeadersCollection.CreateNewElement("add");
addElement3.Properties.Item("header").Value = "header2";
allowHeadersCollection.AddElement(addElement3);


var allowMethodsCollection = addElement1.ChildElements.Item("allowMethods").Collection;

var addElement4 = allowMethodsCollection.CreateNewElement("add");
addElement4.Properties.Item("method").Value = "DELETE";
allowMethodsCollection.AddElement(addElement4);


var exposeHeadersCollection = addElement1.ChildElements.Item("exposeHeaders").Collection;

var addElement5 = exposeHeadersCollection.CreateNewElement("add");
addElement5.Properties.Item("header").Value = "header1";
exposeHeadersCollection.AddElement(addElement5);


var addElement6 = exposeHeadersCollection.CreateNewElement("add");
addElement6.Properties.Item("header").Value = "header2";
exposeHeadersCollection.AddElement(addElement6);

corsCollection.AddElement(addElement1);


var addElement7 = corsCollection.CreateNewElement("add");
addElement7.Properties.Item("origin").Value = "http://*";
addElement7.Properties.Item("allowed").Value = false;
corsCollection.AddElement(addElement7);


adminManager.CommitChanges();

命令列 (AppCmd)

appcmd.exe set config "contentSite" -section:system.webServer/cors /enabled:"True" /failUnlistedOrigins:"True"

appcmd.exe set config "contentSite" -section:system.webServer/cors /+"[origin='*']"

appcmd.exe set config "contentSite" -section:system.webServer/cors /+"[origin='https://*.microsoft.com',allowCredentials='True',maxAge='120']"
appcmd.exe set config "contentSite" -section:system.webServer/cors /[origin='https://*.microsoft.com',allowCredentials='True',maxAge='120'].allowHeaders.allowAllRequestedHeaders:"True"

appcmd.exe set config "contentSite" -section:system.webServer/cors /+"[origin='https://*.microsoft.com',allowCredentials='True',maxAge='120'].allowHeaders.[header='header1']"

appcmd.exe set config "contentSite" -section:system.webServer/cors /+"[origin='https://*.microsoft.com',allowCredentials='True',maxAge='120'].allowHeaders.[header='header2']"

appcmd.exe set config "contentSite" -section:system.webServer/cors /+"[origin='https://*.microsoft.com',allowCredentials='True',maxAge='120'].allowMethods.[method='DELETE']"

appcmd.exe set config "contentSite" -section:system.webServer/cors /+"[origin='https://*.microsoft.com',allowCredentials='True',maxAge='120'].exposeHeaders.[header='header1']"

appcmd.exe set config "contentSite" -section:system.webServer/cors /+"[origin='https://*.microsoft.com',allowCredentials='True',maxAge='120'].exposeHeaders.[header='header2']"

appcmd.exe set config "contentSite" -section:system.webServer/cors /+"[origin='http://*',allowed='False']"

PowerShell

Set-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST/contentSite'  -filter "system.webServer/cors" -name "enabled" -value "True"
Set-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST/contentSite'  -filter "system.webServer/cors" -name "failUnlistedOrigins" -value "True"

Add-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST/contentSite'  -filter "system.webServer/cors" -name "." -value @{origin='*'}

Add-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST/contentSite'  -filter "system.webServer/cors" -name "." -value @{origin='https://*.microsoft.com';allowCredentials='True';maxAge=120}
Set-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST/contentSite'  -filter "system.webServer/cors/add[@origin='https://*.microsoft.com']/allowHeaders" -name "allowAllRequestedHeaders" -value "True"

Add-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST/contentSite'  -filter "system.webServer/cors/add[@origin='https://*.microsoft.com']/allowHeaders" -name "." -value @{header='header1'}

Add-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST/contentSite'  -filter "system.webServer/cors/add[@origin='https://*.microsoft.com']/allowHeaders" -name "." -value @{header='header2'}

Add-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST/contentSite'  -filter "system.webServer/cors/add[@origin='https://*.microsoft.com']/allowMethods" -name "." -value @{method='DELETE'}

Add-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST/contentSite'  -filter "system.webServer/cors/add[@origin='https://*.microsoft.com']/exposeHeaders" -name "." -value @{header='header1'}

Add-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST/contentSite'  -filter "system.webServer/cors/add[@origin='https://*.microsoft.com']/exposeHeaders" -name "." -value @{header='header2'}

Add-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST/contentSite'  -filter "system.webServer/cors" -name "." -value @{origin='http://*';allowed='False'}