IIS CORS 模块配置参考

由 IIS 团队

本文概述了 IIS CORS 模块,并说明了模块的配置。

功能概述

Microsoft IIS CORS 模块是一个扩展,使网站能够支持 CORS (跨域资源共享) 协议。

IIS CORS 模块为 Web 服务器管理员和网站作者提供了一种方法,使其应用程序支持 CORS 协议。 借助此模块,开发人员可以将 CORS 逻辑移出其应用程序并依赖 Web 服务器。 模块对 CORS 请求的处理由配置中定义的规则决定。 可以轻松定义或配置这些 CORS 规则,以便轻松地将所有 CORS 协议处理委托给模块。

IIS CORS 模块是服务器端 CORS 组件

CORS 协议控制客户端/服务器通信。 通常,Web 浏览器充当客户端 CORS 组件,而 IIS 服务器在 IIS CORS 模块的帮助下充当服务器端 CORS 组件。

当协议感知客户端(如 Web 浏览器)向与当前域不同的域 (源) 发出请求时,会发生 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 服务器或特定 IIS 站点、应用程序、虚拟目录、物理目录或 system.webServer/cors) (文件启用、禁用 CORS。
  2. 将所有源主机域配置为使用 * 源主机规则接受。
  3. 配置特定源主机域的列表,并仅允许与列出的源主机域之一具有相同的源请求标头值的 CORS 请求。
  4. 配置源域列表时配置野生卡源主机域,例如 http://*https://*.mydomain.com
  5. 配置应禁止作为 CORS 请求的源域列表。
  6. 使用配置的值自定义 CORS 响应标头值。

cors 元素的属性

Attribute 说明
enabled 可选布尔属性。
指定是否启用 CORS。
默认值为 false
failUnlistedOrigins 可选布尔属性。
指定如果请求的源与配置的源列表不匹配,或者源主机配置为不允许,是否要使用 403 设置 CORS 响应状态代码。
默认值为 false

添加源规则 <添加>

源规则

集合 <add><cors> 元素指定要添加到源规则列表的单个原点。

源规则的属性

Attribute 说明
origin 必需的字符串属性。
指定要对其施加源规则的源主机。 可以使用星号 (*) 将此规则应用于所有源请求标头值。 还可以使用星号 (*) 作为子子域名称的通配符。 如果有多个源规则,则无论允许的属性值如何,它都会应用于最具体的源主机名规则。
allowed 可选布尔属性。
指定是否接受源主机的 CORS 请求。
默认值为 true
allowCredentials 可选布尔属性。
指定是否设置 Access-Control-Allow-Credentials: true CORS 响应标头。 此属性应仅用于特定源主机名,而不是 * 源主机,以符合 CORS 协议。
默认值为 false
maxAge 可选的整数属性。 持续时间(以秒为单位)。
指定预检 CORS 请求的响应标头的值 Access-Control-Max-Age 。 应仅为 CORS 预检请求设置 Access-Control-Max-Age 响应标头。 如果不想在 CORS 响应中设置 Access-Control-Max-Age 标头,请为此属性设置 -1。
默认值为 -1

仅使用 * 源主机规则

如果只有 * 源主机规则,则 IIS CORS 模块与存在特定源主机名规则时的行为不同。 如果只有 * 源主机规则,IIS CORS 模块将执行以下操作:

  1. 无论客户端 CORS 组件发送的请求标头的值如何,Access-Control-Allow-Origin 响应标头的值 origin 都设置为 *。
  2. Vary: origin 未添加响应标头,因为 IIS CORS 不会生成除 * 以外的 Access-Control-Allow-Origin 响应标头值,并且无需使用 Vary: origin 响应标头值。

源主机规则的子元素

元素 说明
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 配置 exposeHeaders 集合,该集合用于源主机规则中指定的主机的 CORS 响应标头的值Access-Control-Expose-Headers
Access-Control-Expose-Headers 仅为实际 CORS 请求设置响应标头,而不是为预检请求设置。

allowHeaders 元素的属性

Attribute 说明
allowAllRequestedHeaders 可选布尔属性。 如果为 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'}