Referencia de configuración del módulo CORS de IIS

por el equipo de IIS

En este artículo se proporciona información general sobre el módulo CORS de IIS y se explica la configuración del módulo.

Introducción a la funcionalidad

El módulo CORS de Microsoft IIS es una extensión que permite a los sitios web admitir el protocolo CORS(uso compartido de recursos entre orígenes).

El módulo CORS de IIS proporciona una manera de que los administradores de servidores web y los autores de sitios web hagan que sus aplicaciones admitan el protocolo CORS. Con este módulo, los desarrolladores pueden mover la lógica de CORS fuera de sus aplicaciones y confiar en el servidor web. El control del módulo de solicitudes CORS viene determinado por las reglas definidas en la configuración. Estas reglas de CORS se pueden definir o configurar fácilmente, lo que facilita la delegación de todo el control de protocolos CORS al módulo.

El módulo CORS de IIS es un componente CORS del lado servidor

El protocolo CORS rige la comunicación de cliente/servidor. Normalmente, los exploradores web actúan como componente CORS del lado cliente, mientras que el servidor IIS funciona como componente CORS del lado servidor con la ayuda del módulo CORS de IIS.

Una solicitud CORS se produce cuando un cliente compatible con protocolos, como un explorador web, realiza una solicitud a un dominio (origen) que difiere del dominio actual. Este escenario se conoce como una solicitud de origen cruzado. Cuando no se usa CORS, el cliente bloqueará las solicitudes entre orígenes. Cuando se usa el módulo CORS, IIS informará a los clientes de si se puede realizar una solicitud entre orígenes en función de la configuración de IIS.

Solicitud preliminar de CORS

Se utiliza una solicitud de preconsulta de CORS para determinar si el recurso solicitado está configurado para ser compartido entre orígenes por el servidor. La comprobación previa de CORS usa el método HTTPOPTIONS con los encabezados de solicitud ACCESS-CONTROL-REQUEST-METHOD y ORIGIN. El módulo CORS de IIS está diseñado para controlar las solicitudes preparatorias de CORS antes de que otros módulos de IIS controle la misma solicitud. Las solicitudes OPTIONS siempre son anónimas, por lo que el módulo CORS proporciona a los servidores IIS una manera de responder correctamente a la solicitud preparatoria incluso si es necesario deshabilitar la autenticación anónima en el servidor.

Configuración de CORS

IIS CORS se configura a través de un archivo web.config de un sitio o aplicación y tiene su propia sección de configuración en system.webServer.

A continuación se muestran los ejemplos de configuración para habilitar CORS para un sitio denominado contentSite. El origen * permite todos los orígenes del host; sin embargo, los que comienzan por http://* se excluyen más adelante. Para el origen del https://*.microsoft.com host, la respuesta de CORS se personaliza con varias configuraciones de CORS como ejemplo.

<?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>

Con el módulo CORS de IIS, puede hacer lo siguiente:

  1. Habilite, deshabilite CORS para un servidor IIS completo o para un sitio de IIS específico, una aplicación, un directorio virtual, un directorio físico o un archivo (system.webServer/cors).
  2. Configurar todos los dominios de host de origen para que se acepten con la regla de host de origen *.
  3. Configure la lista de dominios de host de origen específicos y permita solo la solicitud CORS que tiene el mismo valor del encabezado de solicitud de origen que uno de los dominios de host de origen enumerados.
  4. Configure los dominios de host de origen comodín al elaborar la lista de dominios de origen, como http://* o https://*.mydomain.com.
  5. Configure una lista de dominios de origen que no se deben permitir como solicitud CORS.
  6. Personalice los valores de encabezado de respuesta de CORS con los valores configurados.

Atributos del elemento cors

Atributo Descripción
enabled Atributo Boolean opcional.
Especifica si CORS está habilitado.
El valor predeterminado es false.
failUnlistedOrigins Atributo Boolean opcional.
Especifica si el código de estado de la respuesta CORS debe establecerse en 403 si el origen solicitado no coincide con la lista configurada de orígenes o si el host de origen está configurado como no permitido.
El valor predeterminado es false.

Añadiendo regla de origen <add>

Reglas de origen

El <add> elemento de la <cors> colección especifica un origen individual que se va a agregar a la lista de reglas de origen.

Atributos de la regla de origen

Atributo Descripción
origin Atributo de cadena necesario.
Especifica el host de origen en el que se va a imponer una regla de origen. Puede usar un asterisco (*) para aplicar esta regla a todos los valores de encabezado de solicitud de origen. También puede usar un asterisco (*) como carácter comodín para el nombre del subdominio hijo. Si hay varias reglas de origen, se aplica a la regla de nombre de host de origen más específica, independientemente del valor de atributo permitido.
allowed Atributo Boolean opcional.
Especifica si se va a aceptar la solicitud CORS para el host de origen.
El valor predeterminado es true.
allowCredentials Atributo Boolean opcional.
Especifica si se debe establecer el encabezado de respuesta CORS Access-Control-Allow-Credentials: true. Este atributo solo debe usarse para un nombre de host de origen específico en lugar de * host de origen para el cumplimiento del protocolo CORS.
El valor predeterminado es false.
maxAge Atributo integer opcional. Duración en segundos.
Especifica el valor del encabezado de Access-Control-Max-Age respuesta para la solicitud CORS de pre-vuelo. Se supone que el encabezado de la respuesta Access-Control-Max-Age debe establecerse solo para las solicitudes de verificación previa de CORS. Si no desea establecer el encabezado Access-Control-Max-Age en la respuesta CORS, establezca -1 para este atributo.
El valor predeterminado es -1.

Uso únicamente de la regla de host de origen

Si solo hay una regla de host de origen * , el módulo CORS de IIS tiene algunos comportamientos diferentes en comparación con cuando hay una regla de nombre de host de origen específica. Si solo hay una regla de host de origen * , el módulo CORS de IIS hace lo siguiente:

  1. El valor del encabezado de respuesta Access-Control-Allow-Origin se establece en * independientemente del valor del encabezado de solicitud origin enviado por el componente CORS del lado del cliente.
  2. Vary: origin no se agrega el encabezado de respuesta porque IIS CORS no genera el encabezado de respuesta Access-Control-Allow-Origin con valores distintos de * y no es necesario usar el valor del encabezado Vary: origin.

Elementos secundarios de la regla de origen del host

Elemento Descripción
allowHeaders configura la colección allowHeaders que se utiliza para el valor del encabezado de respuesta CORS del host de origen especificado en la regla de host de origen.
El Access-Control-Allow-Headers encabezado de respuesta se establecerá solamente para las solicitudes CORS reales en lugar de para las solicitudes preliminares.
allowMethods configura la colección allowMethods que se utiliza para el valor de la cabecera de respuesta CORS del host de origen especificado en la regla de host de origen.
El Access-Control-Allow-Methods encabezado de respuesta solo se establecerá para las solicitudes preparatorias de CORS.
exposeHeaders configura la colección exposeHeaders que se usa para el valor del encabezado de Access-Control-Expose-Headers respuesta CORS para el host de origen especificado en la regla de host de origen.
El Access-Control-Expose-Headers encabezado de respuesta solo se establecerá para las solicitudes CORS reales en lugar de para las solicitudes de preflight.

Atributos del elemento allowHeaders

Atributo Descripción
allowAllRequestedHeaders Atributo Boolean opcional. Si esto es verdadero, el módulo IIS tomará el valor del encabezado de solicitud Access-Control-Request-Headers CORS y establecerá el encabezado de respuesta Access-Control-Allow-Headers con el mismo valor, lo que significa que se permiten los encabezados proporcionados. Si esto es falso, establece el encabezado de respuesta Access-Control-Allow-Headers con los valores de encabezado de la colección allowHeaders, lo que implica que solo se permiten los encabezados enumerados. El valor predeterminado es false.

Código de ejemplo

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();

Línea de comandos (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'}