Pergunta

Existe uma maneira de permitir que várias cruzadas domínios usando o cabeçalho Access-Control-Allow-Origin?

Estou ciente da *, mas é muito aberto. Eu realmente quero permitir que apenas alguns domínios.

Como exemplo, algo como isto:

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

Eu tentei o código acima, mas não parecem funcionar no Firefox.

É possível especificar vários domínios ou estou preso com apenas um?

Foi útil?

Solução

Parece que a maneira recomendada de fazer isso é para que o servidor ler o cabeçalho de Origem a partir do cliente, que ao comparar a lista de domínios que você gostaria de permitir, e se ele corresponde, ecoar o valor do cabeçalho de volta Origin para o cliente como o cabeçalho Access-Control-Allow-Origin na resposta.

Com .htaccess você pode fazê-lo como este:

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

Outras dicas

Outra solução que estou usando no 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");
}

Isso funcionou para mim:

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

Ao colocar em .htaccess, que vai funcionar com certeza.

Eu tive o mesmo problema com WOFF-fonts, vários subdomínios tinha que ter acesso. Para permitir que os subdomínios I acrescentou algo como isto ao meu 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 vários domínios você pode simplesmente mudar o regex em SetEnvIf.

Veja como ecoar a volta cabeçalho Origem se ele corresponde a seu domínio com Nginx, isto é útil se você quiser servir a um múltiplo da fonte sub-domínios:

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

Aqui está o que eu fiz para uma aplicação PHP que está sendo solicitado pelo 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);
}

Se a origem solicitando é permitido pelo meu servidor, voltar a própria $http_origin como valor do cabeçalho Access-Control-Allow-Origin vez de retornar um curinga *.

Há uma desvantagem que você deve estar ciente: Assim que os arquivos que você out-source para um CDN (ou qualquer outro servidor que não permite scripting) ou se seus arquivos são armazenados em cache em um proxy, alterando a resposta com base em 'Origem' cabeçalho de solicitação não vai funcionar.

Para vários domínios, em sua .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>

Usuários para Nginx para permitir CORS para vários domínios. Eu gosto do @ exemplo de Marshall embora seus anwers corresponde apenas um domínio. Para corresponder a uma lista de domínio e subdomínio isso faz regex-lhe a facilidade de trabalhar com fontes:

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";
   }
}

Isso só vai echo "Access-Control-Allow-Origin" cabeçalhos que combina com a lista dada de domínios.

Para o IIS 7.5+ com URL Rewrite 2,0 módulo instalado consulte esta resposta SO

Aqui está uma solução para o aplicativo web Java, com base na resposta do yesthatguy.

Eu estou usando Jersey RESTO 1.x

Configurar o web.xml para estar ciente de Jersey REST e o 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>

Aqui está o 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 mencionado acima, Access-Control-Allow-Origin deve ser único e Vary deve ser definido como Origin se você está atrás de um CDN (Content Delivery Network).

parte relevante da minha configuração 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';
}

Talvez eu esteja errado, mas tanto quanto eu posso ver Access-Control-Allow-Origin tem uma "origin-list" como parâmetro.

definição um origin-list é:

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

E a partir deste, defendo diferentes origens são admitidos e deve ser espaço separado .

Eu lutei para configurá-lo para um domínio que executa o HTTPS, então eu percebi que eu iria compartilhar a solução. Eu usei a seguinte diretiva na minha httpd.conf arquivo:

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

Alterar example.com ao seu nome de domínio. Adicione esta <VirtualHost x.x.x.x:xx> dentro em sua httpd.conf arquivo. Observe que se o seu VirtualHost tem um sufixo de porta (por exemplo :80), em seguida, esta directiva não se aplicará a HTTPS, assim que você também precisa ir ao / etc / apache2 / sites-available / default-ssl e adicionar a mesma directiva nesse arquivo, dentro da seção <VirtualHost _default_:443>.

Uma vez que os arquivos de configuração são atualizados, você terá de executar os seguintes comandos no terminal:

a2enmod headers
sudo service apache2 reload

Se você está tendo problemas com fontes, use:

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

Para aplicações ExpressJS você pode 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 não é usado por todos os navegadores. Quão seguro é HTTP_ORIGIN? Para mim, trata-se vazio no FF.
Eu tenho os sites que eu permitir o acesso ao meu site enviar mais de um ID do site, então eu verificar o meu DB para o registro com que ID e obter o valor da coluna SITE_URL (www.yoursite.com).

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

Mesmo se a enviar mais de um ID do site válidas as necessidades pedido para ser do domínio listado no meu DB associada a esse ID site.

Aqui está uma opção expandida para apache que inclui algumas das definições mais recente e planejada fonte:

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

E mais uma resposta em Django. Para ter uma visão única permitir CORS de vários domínios, aqui está o meu 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 obter uma cópia bastante fácil / colar para aplicações .NET, eu escrevi isso para permitir CORS de dentro de um arquivo global. Este código segue o conselho dado na resposta atualmente aceita, refletindo o que quer voltar origem é dada no pedido na resposta. Isto consegue efetivamente '*' sem usá-lo. A razão para isso é que ele permite que várias outras características CORS, incluindo a capacidade de enviar um AJAX XMLHttpRequest com conjunto de atributos dos withCredentials 'para 'true'.

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 o acesso de vários domínios para um serviço ASMX, eu criei esta função no arquivo global:

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

Isto permite CORS manipulação de OPTIONS verbo também.

PHP exemplo de código para subdomínios correspondentes.

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

Uma abordagem mais flexível é usar expressões Apache 2.4 do. Você pode combinar contra domínios, caminhos, e apenas sobre cada outra variável pedido. Embora a resposta é * para todos, os únicos solicitantes recebem essa resposta são os que atendem aos requisitos de qualquer maneira.

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

resposta suporte do Google em veiculando anúncios sobre SSL e gramática na própria RFC parece indicar que você pode espaço delimitar as URLs. Não sei como bem suportado isto é, em diferentes browsers.

Se você tentar tantos exemplos de código como eu para fazê-lo funcionar usando CORS, vale a pena mencionar que você tem que limpar o cache primeiro para tentar se ele realmente funciona, semelhante a questões como quando imagens antigas ainda estão presentes, mesmo que seja excluído no servidor (porque ele ainda está guardada no seu cache).

Por exemplo CTRL + SHIFT + DEL no Google Chrome para apagar o cache.

Isso me ajudou usando este código depois de tentar muitas soluções pura .htaccess e este parecia o único trabalho (pelo menos para mim):

    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>

Além disso, note que é amplamente difundido que muitas soluções de dizer que você tem que digitar Header set ... mas é Header add .... Espero que isso ajude alguém que tenha os mesmos problemas para algumas horas, agora como eu.

Abaixo resposta é específica para C #, mas o conceito deve ser aplicável a todas as diferentes plataformas.

Para permitir solicitações entre Origem de uma API web, você precisa para permitir solicitações de opção para a sua aplicação e Adicionar abaixo anotação ao nível do controlador.

[EnableCors (URLString, Cabeçalho, Method)] Agora as origens podem ser passados ??apenas uma string s. Então, se você quer passar mais de um URL na solicitação de passá-lo como um valor separado por vírgulas.

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

Apenas uma única origem pode ser especificada para o cabeçalho Access-Control-Allow-Origin. Mas você pode definir a origem na sua resposta de acordo com o pedido. Também não se esqueça de definir o cabeçalho Vary. No PHP eu faria o seguinte:

    /**
     * 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
  }

Nós também podemos definir isso no arquivo global para aplicação Asp.net.

protected void Application_BeginRequest(object sender, EventArgs e)
    {

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

    }

A resposta parece ser a de usar o cabeçalho mais de uma vez. Ou seja, em vez 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

No Apache, você pode fazer isso em uma seção httpd.conf <VirtualHost> ou arquivo .htaccess usando mod_headers e esta sintaxe:

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"

O truque é usar add em vez de append como o primeiro argumento.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top