Pregunta

¿Hay una manera de permitir que varios dominios cruzados usando la cabecera Access-Control-Allow-Origin?

Soy consciente de la *, pero es demasiado abierta. Realmente quiero permitir que sólo un par de dominios.

A modo de ejemplo, algo como esto:

Access-Control-Allow-Origin: http://domain1.example, http://domain2.example

He probado el código anterior pero no parecen funcionar en Firefox.

Es posible especificar varios dominios o estoy atascado con sólo uno?

¿Fue útil?

Solución

suena como la forma recomendada para hacerlo es tener su servidor lee el encabezado de origen del cliente, que para comparar la lista de dominios que le gustaría permitir, y si coincide, eco del valor de la cabecera Origin vuelta al cliente como el encabezado Access-Control-Allow-Origin en la respuesta.

Con .htaccess puede hacerlo de esta manera:

# ----------------------------------------------------------------------
# Allow loading of external fonts
# ----------------------------------------------------------------------
<FilesMatch "\.(ttf|otf|eot|woff|woff2)$">
    <IfModule mod_headers.c>
        SetEnvIf Origin "http(s)?://(www\.)?(google.com|staging.google.com|development.google.com|otherdomain.example|dev02.otherdomain.example)$" AccessControlAllowOrigin=$0
        Header add Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin
        Header merge Vary Origin
    </IfModule>
</FilesMatch>

Otros consejos

Otra solución que estoy usando en PHP:

$http_origin = $_SERVER['HTTP_ORIGIN'];

if ($http_origin == "http://www.domain1.com" || $http_origin == "http://www.domain2.com" || $http_origin == "http://www.domain3.com")
{  
    header("Access-Control-Allow-Origin: $http_origin");
}

Esto funcionó para mí:

SetEnvIf Origin "^http(s)?://(.+\.)?(domain\.example|domain2\.example)$" origin_is=$0 
Header always set Access-Control-Allow-Origin %{origin_is}e env=origin_is

Cuando se ponen en .htaccess, que funcionará con seguridad.

Yo tenía el mismo problema con WOFF-fonts, varios subdominios tenía que tener acceso. Para permitir que los subdominios que añaden algo como esto a mi httpd.conf:

SetEnvIf Origin "^(.*\.example\.com)$" ORIGIN_SUB_DOMAIN=$1
<FilesMatch "\.woff$">
    Header set Access-Control-Allow-Origin "%{ORIGIN_SUB_DOMAIN}e" env=ORIGIN_SUB_DOMAIN
</FilesMatch>

Para múltiples dominios que sólo podría cambiar la expresión regular en SetEnvIf.

Aquí es cómo hacen eco de la cabecera Origen de regreso si coincide con su dominio con Nginx, esto es útil si desea servir una fuente múltiples sub-dominios:

location /fonts {
    # this will echo back the origin header
    if ($http_origin ~ "example.org$") {
        add_header "Access-Control-Allow-Origin" $http_origin;
    }
}

Esto es lo que hice para una aplicación PHP que está siendo solicitado por AJAX

$request_headers        = apache_request_headers();
$http_origin            = $request_headers['Origin'];
$allowed_http_origins   = array(
                            "http://myDumbDomain.example"   ,
                            "http://anotherDumbDomain.example"  ,
                            "http://localhost"  ,
                          );
if (in_array($http_origin, $allowed_http_origins)){  
    @header("Access-Control-Allow-Origin: " . $http_origin);
}

Si el origen solicitante está permitido por mi servidor, devolver el $http_origin como valor de la cabecera Access-Control-Allow-Origin en lugar de devolver un comodín *.

No es una desventaja que debe tener en cuenta: Tan pronto como archivos de subcontratar a un CDN (o cualquier otro servidor que no permite scripting) o si sus archivos se almacenan en caché en un proxy, la alteración de la respuesta basada en encabezado de la solicitud 'origen' no funcionará.

Para varios dominios, en su .htaccess:

<IfModule mod_headers.c>
    SetEnvIf Origin "http(s)?://(www\.)?(domain1.example|domain2.example)$" AccessControlAllowOrigin=$0$1
    Header add Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin
    Header set Access-Control-Allow-Credentials true
</IfModule>

Para los usuarios Nginx para permitir CORS para varios dominios. Me gusta el ejemplo de Marshall @ aunque sus anwers sólo coincide con un dominio. Para que coincida con una lista de dominio y subdominio esta expresión regular que sea la facilidad para trabajar con fuentes:

location ~* \.(?:ttf|ttc|otf|eot|woff|woff2)$ {
   if ( $http_origin ~* (https?://(.+\.)?(domain1|domain2|domain3)\.(?:me|co|com)$) ) {
      add_header "Access-Control-Allow-Origin" "$http_origin";
   }
}

Esto sólo se hará eco de las cabeceras "Access-Control-Allow-Origin" que coincide con la lista dada de dominios.

Para IIS 7.5+ con el módulo de reescritura de URL 2.0 instalado consulte este SO responder

Aquí hay una solución para aplicación web de Java, basado en la respuesta de yesthatguy.

Estoy utilizando Jersey RESTO 1.x

Configurar el web.xml para estar al tanto de Jersey REST y la CORSResponseFilter

 <!-- Jersey REST config -->
  <servlet>    
    <servlet-name>JAX-RS Servlet</servlet-name>
    <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
    <init-param> 
        <param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
        <param-value>true</param-value>
    </init-param>
    <init-param>
      <param-name>com.sun.jersey.spi.container.ContainerResponseFilters</param-name>
      <param-value>com.your.package.CORSResponseFilter</param-value>
    </init-param>   
    <init-param>
        <param-name>com.sun.jersey.config.property.packages</param-name>
        <param-value>com.your.package</param-value>
    </init-param>        
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>JAX-RS Servlet</servlet-name>
    <url-pattern>/ws/*</url-pattern>
  </servlet-mapping>

Aquí está el código para CORSResponseFilter

import com.sun.jersey.spi.container.ContainerRequest;
import com.sun.jersey.spi.container.ContainerResponse;
import com.sun.jersey.spi.container.ContainerResponseFilter;


public class CORSResponseFilter implements ContainerResponseFilter{

@Override
public ContainerResponse filter(ContainerRequest request,
        ContainerResponse response) {

    String[] allowDomain = {"http://localhost:9000","https://my.domain.example"};
    Set<String> allowedOrigins = new HashSet<String>(Arrays.asList (allowDomain));                  

    String originHeader = request.getHeaderValue("Origin");

    if(allowedOrigins.contains(originHeader)) {
        response.getHttpHeaders().add("Access-Control-Allow-Origin", originHeader);

        response.getHttpHeaders().add("Access-Control-Allow-Headers",
                "origin, content-type, accept, authorization");
        response.getHttpHeaders().add("Access-Control-Allow-Credentials", "true");
        response.getHttpHeaders().add("Access-Control-Allow-Methods",
                "GET, POST, PUT, DELETE, OPTIONS, HEAD");
    }

    return response;
}

}

Como se mencionó anteriormente, Access-Control-Allow-Origin debe ser único y Vary se debe establecer en Origin si está detrás de un CDN (Content Delivery Network).

Parte pertinente de mi configuración de Nginx:

if ($http_origin ~* (https?://.*\.mydomain.example(:[0-9]+)?)) {
  set $cors "true";
}
if ($cors = "true") {
  add_header 'Access-Control-Allow-Origin' "$http_origin";
  add_header 'X-Frame-Options' "ALLOW FROM $http_origin";
  add_header 'Access-Control-Allow-Credentials' 'true';
  add_header 'Vary' 'Origin';
}

Tal vez estoy equivocado, pero por lo que puedo ver Access-Control-Allow-Origin tiene un "origin-list" como parámetro.

definición un origin-list es:

origin            = "origin" ":" 1*WSP [ "null" / origin-list ]
origin-list       = serialized-origin *( 1*WSP serialized-origin )
serialized-origin = scheme "://" host [ ":" port ]
                  ; <scheme>, <host>, <port> productions from RFC3986

Y a partir de esto, sostengo diferentes orígenes son admitidos y deben ser espacio separado .

Luché para configurar esto para un dominio con HTTPS, por lo que pensé que iba a compartir la solución. He utilizado la siguiente directiva en mi httpd.conf file:

    <FilesMatch "\.(ttf|otf|eot|woff)$">
            SetEnvIf Origin "^http(s)?://(.+\.)?example\.com$" AccessControlAllowOrigin=$0
            Header set Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin
    </FilesMatch>

Cambiar example.com a su nombre de dominio. Añadir este <VirtualHost x.x.x.x:xx> dentro de su archivo httpd.conf . Observe que si su VirtualHost tiene un sufijo de puerto (por ejemplo :80) entonces esta directiva no se aplicará a HTTPS, por lo que tendrá que ir también a / etc / apache2 / sites-available / default-ssl y añadir la misma Directiva en ese archivo, dentro de la sección <VirtualHost _default_:443>.

Una vez que los archivos de configuración se actualizan, se tendrá que ejecutar los siguientes comandos en el terminal:

a2enmod headers
sudo service apache2 reload

Si usted está teniendo problemas con las fuentes, utilice:

<FilesMatch "\.(ttf|ttc|otf|eot|woff)$">
    <IfModule mod_headers>
        Header set Access-Control-Allow-Origin "*"
    </IfModule>
</FilesMatch>

Para aplicaciones ExpressJS puede usar:

app.use((req, res, next) => {
    const corsWhitelist = [
        'https://domain1.example',
        'https://domain2.example',
        'https://domain3.example'
    ];
    if (corsWhitelist.indexOf(req.headers.origin) !== -1) {
        res.header('Access-Control-Allow-Origin', req.headers.origin);
        res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
    }

    next();
});

HTTP_ORIGIN no es utilizada por todos los navegadores. ¿Qué tan seguro es HTTP_ORIGIN? Para mí se trata con las manos vacías en FF.
Tengo los sitios que permiten el acceso a mi sitio enviar a través de un identificador de sitio, y luego revisar mi base de datos para el registro con ese ID y obtener el valor de la columna SITE_URL (www.yoursite.com).

header('Access-Control-Allow-Origin: http://'.$row['SITE_URL']);

Aunque el envío de más de un identificador de sitio válida la solicitud tiene que ser del dominio que aparece en mi DB asociado con ese identificador de sitio.

Esta es una opción ampliado para Apache que incluye algunas de las últimas definiciones de fuente y planificadas:

<FilesMatch "\.(ttf|otf|eot|woff|woff2|sfnt|svg)$">
    <IfModule mod_headers.c>
        SetEnvIf Origin "^http(s)?://(.+\.)?(domainname1|domainname2|domainname3)\.(?:com|net|org)$" AccessControlAllowOrigin=$0$1$2
        Header add Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin
        Header set Access-Control-Allow-Credentials true
    </IfModule>
</FilesMatch>

Y una respuesta más en Django. Para tener una visión única permite CORS de múltiples dominios, aquí está mi código:

def my_view(request):
    if 'HTTP_ORIGIN' in request.META.keys() and request.META['HTTP_ORIGIN'] in ['http://allowed-unsecure-domain.com', 'https://allowed-secure-domain.com', ...]:
        response = my_view_response() # Create your desired response data: JsonResponse, HttpResponse...
        # Then add CORS headers for access from delivery
        response["Access-Control-Allow-Origin"] = request.META['HTTP_ORIGIN']
        response["Access-Control-Allow-Methods"] = "GET" # "GET, POST, PUT, DELETE, OPTIONS, HEAD"
        response["Access-Control-Max-Age"] = "1000"  
        response["Access-Control-Allow-Headers"] = "*"  
        return response

Para obtener una copia bastante fácil / pegar para aplicaciones .NET, escribí esta opción para activar CORS dentro de un archivo Global.asax. Este código sigue los consejos dados en la respuesta aceptada actualmente, lo que refleja lo que sea posterior origen se da en la solicitud en la respuesta. Con esto se logra de manera efectiva '*' sin usarlo. La razón de esto es que permite múltiples otras características CORS, incluyendo la capacidad de enviar un XMLHttpRequest AJAX con el atributo '' withCredentials ajustado a 'verdadero'.

void Application_BeginRequest(object sender, EventArgs e)
{
    if (Request.HttpMethod == "OPTIONS")
    {
        Response.AddHeader("Access-Control-Allow-Methods", "GET, POST");
        Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept");
        Response.AddHeader("Access-Control-Max-Age", "1728000");
        Response.End();
    }
    else
    {
        Response.AddHeader("Access-Control-Allow-Credentials", "true");

        if (Request.Headers["Origin"] != null)
            Response.AddHeader("Access-Control-Allow-Origin" , Request.Headers["Origin"]);
        else
            Response.AddHeader("Access-Control-Allow-Origin" , "*");
    }
}

Para facilitar el acceso de múltiples dominios para un servicio de ASMX, creé esta función en el archivo Global.asax:

protected void Application_BeginRequest(object sender, EventArgs e)
{
    string CORSServices = "/account.asmx|/account2.asmx";
    if (CORSServices.IndexOf(HttpContext.Current.Request.Url.AbsolutePath) > -1)
    {
        string allowedDomains = "http://xxx.yyy.example|http://aaa.bbb.example";

        if(allowedDomains.IndexOf(HttpContext.Current.Request.Headers["Origin"]) > -1)
            HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", HttpContext.Current.Request.Headers["Origin"]);

        if(HttpContext.Current.Request.HttpMethod == "OPTIONS")
            HttpContext.Current.Response.End();
    }
}

Esto permite CORS manejo de OPTIONS verbo también.

ejemplo de código PHP para hacer coincidir los subdominios.

if( preg_match("/http:\/\/(.*?)\.yourdomain.example/", $_SERVER['HTTP_ORIGIN'], $matches )) {
        $theMatch = $matches[0];
        header('Access-Control-Allow-Origin: ' . $theMatch);
}

Un enfoque más flexible es el uso de expresiones de Apache 2.4. Se puede sincronizar contra dominios, caminos y casi cualquier otra variable de petición. Aunque la respuesta es * para todos, los únicos que reciben los solicitantes que la respuesta son los que cumplen con los requisitos de todos modos.

<IfModule mod_headers.c>
    <If "%{HTTP:Host} =~ /\\bcdndomain\\.example$/i && %{HTTP:Origin} =~ /\\bmaindomain\\.example$/i">
        Header set Access-Control-Allow-Origin "*"
    </If>
</IfModule>

Respuesta de soporte de Google en la publicación de anuncios a través de SSL y la la gramática en el propio RFC parecería indicar que se puede delimitar el espacio de las direcciones URL. No estoy seguro como bien soportado esto es en diferentes navegadores.

Si intenta tantos ejemplos de código como yo para hacer que funcione utilizando CORS, vale la pena mencionar que usted tiene que borrar la memoria caché primeros en probar si realmente funciona, de forma similar a cuestiones como cuando las imágenes antiguas todavía están presentes, incluso si se elimina en el servidor (ya que todavía se guarda en la memoria caché).

Por ejemplo CTRL + SHIFT + DEL en Google Chrome para borrar la memoria caché.

Esto me ayudó con este código después de probar muchas soluciones pura .htaccess y esto parecía ser el único que trabaja (al menos para mí):

    Header add Access-Control-Allow-Origin "http://google.com"
    Header add Access-Control-Allow-Headers "authorization, origin, user-token, x-requested-with, content-type"
    Header add Access-Control-Allow-Methods "PUT, GET, POST, DELETE, OPTIONS"

    <FilesMatch "\.(ttf|otf|eot|woff)$">
        <IfModule mod_headers.c>
            SetEnvIf Origin "http(s)?://(www\.)?(google.com|staging.google.com|development.google.com|otherdomain.com|dev02.otherdomain.net)$" AccessControlAllowOrigin=$0
            Header add Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin
        </IfModule>
    </FilesMatch>

También tenga en cuenta que se encuentra ampliamente extendida de que muchas soluciones que usted tiene que escribir Header set ... pero es Header add .... Esperamos que esto ayude a alguien que tiene los mismos problemas para algunas horas ahora como yo.

A continuación la respuesta es específica para C #, pero el concepto debería ser aplicable a todas las diferentes plataformas.

Para permitir solicitudes Cruz origen a partir de una API web, es necesario para permitir solicitudes de opción a su aplicación y agregar a continuación anotación a nivel de controlador.

[EnableCors (urlString, Header, Método)] Ahora los orígenes se pueden pasar solamente una cadena s. Así que si quieres pasar más de una URL en la solicitud de pasarlo como un valor separados por comas.

urlString = " https: //a.hello.com,https: //b.hello.com "

Sólo un único origen se puede especificar para el encabezado Access-Control-Allow-Origin. Sin embargo, se puede establecer el origen de su respuesta de acuerdo a la solicitud. Asimismo, no se olvide de establecer la cabecera Vary. En PHP que haría lo siguiente:

    /**
     * Enable CORS for the passed origins.
     * Adds the Access-Control-Allow-Origin header to the response with the origin that matched the one in the request.
     * @param array $origins
     * @return string|null returns the matched origin or null
     */
    function allowOrigins($origins)
    {
        $val = $_SERVER['HTTP_ORIGIN'] ?? null;
        if (in_array($val, $origins, true)) {
            header('Access-Control-Allow-Origin: '.$val);
            header('Vary: Origin');

            return $val;
        }

        return null;
    }

  if (allowOrigins(['http://localhost', 'https://localhost'])) {
      echo your response here, e.g. token
  }

También podemos configurar esto en el archivo Global.asax para la aplicación Asp.net.

protected void Application_BeginRequest(object sender, EventArgs e)
    {

    // enable CORS
    HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "https://www.youtube.com");

    }

La respuesta parece ser el uso de la cabecera más de una vez. Es decir, en lugar de enviar

Access-Control-Allow-Origin: http://domain1.example, http://domain2.example, http://domain3.example

Enviar

Access-Control-Allow-Origin: http://domain1.example
Access-Control-Allow-Origin: http://domain2.example
Access-Control-Allow-Origin: http://domain3.example

En Apache, puede hacer esto en una sección httpd.conf <VirtualHost> o archivo .htaccess usando mod_headers y esta sintaxis:

Header add Access-Control-Allow-Origin "http://domain1.example"
Header add Access-Control-Allow-Origin "http://domain2.example"
Header add Access-Control-Allow-Origin "http://domain3.example"

El truco es usar add en lugar de append como primer argumento.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top