Acesso-Controlo-Permitir-Origem Domínios De Origem Múltipla?
Existe uma forma de permitir vários domínios cruzados usando o cabeçalho Access-Control-Allow-Origin
?
*
, mas está demasiado aberto. Eu realmente quero permitir apenas alguns domínios.
como exemplo, algo assim:
Access-Control-Allow-Origin: http://domain1.example, http://domain2.example
Tentei o código acima, mas não parece funcionar no Firefox.
é possível especificar vários domínios ou estou preso com apenas um?
26 answers
Soa como a forma recomendada de o fazer é fazer com que o seu servidor leia o cabeçalho de origem do cliente, compare-o com a lista de domínios que gostaria de permitir e, se corresponder, faça eco do valor do cabeçalho Origin
de volta para o cliente como o cabeçalho Access-Control-Allow-Origin
na resposta.
Com .htaccess
podes fazê - lo assim:
# ----------------------------------------------------------------------
# Allow loading of external fonts
# ----------------------------------------------------------------------
<FilesMatch "\.(ttf|otf|eot|woff)$">
<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>
Outra solução que estou a usar em 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");
}
SetEnvIf Origin "^http(s)?://(.+\.)?(domain\.example|domain2\.example)$" origin_is=$0
Header always set Access-Control-Allow-Origin %{origin_is}e env=origin_is
Quando colocado em .htaccess
, vai funcionar de certeza.
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, pode alterar a expressão regular em SetEnvIf
.
Aqui está como fazer eco ao cabeçalho de origem se corresponder ao seu domínio com o Nginx, isto é útil se quiser servir um tipo de letra vários 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á a ser solicitada 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 do pedido for permitida pelo meu servidor, devolve o $http_origin
em si como valor do cabeçalho Access-Control-Allow-Origin
em vez de devolver uma sequência especial *
.
Há uma desvantagem que você deve estar ciente: assim que você sair arquivos de código para um CDN (ou qualquer outro servidor que não permite scripting) ou se seus arquivos são cache em um proxy, alterando a resposta com base no cabeçalho de pedido de 'origem' não vai funcionar.
Para vários domínios, no seu .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 o IIS 7. 5+ com o módulo de reescrita do URL 2. 0 instalado veja por favor isto assim responde
Para os utilizadores do Nginx, permitir o CORS para vários domínios. Gosto do exemplo de @marshall, embora os seus anwers só correspondam a um domínio. Para corresponder a uma lista de domínio e subdomínios, este regex torna mais fácil trabalhar com tipos de letra:
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";
}
}
Isto só fará eco dos cabeçalhos" Access-Control-Allow-Origin" que correspondem à lista de domínios indicada.
Aqui está uma solução para o aplicativo Web Java, baseado na resposta de yesthatguy.
Estou a usar Jersey REST 1.xConfigure a web.xml estar ciente do repouso de Jersey e do 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 {[2] } deve ser definido para Origin
Se estiver por detrás de uma rede de distribuição de conteúdo.
Parte relevante da minha configuração 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';
}
Talvez eu esteja errado, mas tanto quanto posso ver Access-Control-Allow-Origin
tem um "origin-list"
como parâmetro.
Por definição o 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 disto, eu defendo que origens diferentes são admitidas e devem serseparadas por espaço .
<FilesMatch "\.(ttf|otf|eot|woff)$">
SetEnvIf Origin "^http(s)?://(.+\.)?example\.com$" AccessControlAllowOrigin=$0
Header set Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin
</FilesMatch>
Mudar {[2] } para o seu nome de domínio. Adicione isto dentro do <VirtualHost x.x.x.x:xx>
no seu httpd.conf ficheiro. Repare que, se o seu VirtualHost
tiver um sufixo de porto (por exemplo :80
), a presente directiva não se aplica aos HTTPS, pelo que terá de ir também a / etc / apache2/sites-available / default-ssl e adicionar a mesma directiva nesse ficheiro, dentro da Secção <VirtualHost _default_:443>
.
Assim que os ficheiros de configuração forem actualizados, terá de executar os seguintes comandos no terminal:
a2enmod headers
sudo service apache2 reload
Se TEM problemAs com tipos de letra, use:
<FilesMatch "\.(ttf|ttc|otf|eot|woff)$">
<IfModule mod_headers>
Header set Access-Control-Allow-Origin "*"
</IfModule>
</FilesMatch>
O HTTP_ origin não é utilizado por todos os navegadores. Quão seguro é o HTTP_ origin?Para mim, não tem nada em FF.
Eu tenho os sites que eu permitir o acesso ao meu site enviar um ID do site, Eu então verificar o meu DB para o registro com esse id e obter o valor da coluna SITE_URL (www.yoursite.com).
header('Access-Control-Allow-Origin: http://'.$row['SITE_URL']);
Mesmo que o envio de um ID de site válido o pedido precisa ser do domínio listado no meu DB associado a esse ID de site.
Aqui está uma opção expandida para o apache que inclui algumas das mais recentes e planejadas definições de tipos de letra:
<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>
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 facilitar o acesso a vários domínios para um serviço ASMX, criei esta função no global.ficheiro 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();
}
}
Isto também permite a manipulação de CORS de OPTIONS
verbo.
A resposta de suporte do Google em a servir anúncios sobre SSL e a gramática na própria RFC parece indicar que pode delimitar os URLs no espaço. Não sei se isto é bem suportado em diferentes navegadores.
Se você tentar tantos exemplos de código, como eu, para fazer o trabalho usando o CORS, vale a pena mencionar que você tem que limpar seu cache pela primeira vez para tentar se ele realmente funciona, similar a questões como quando imagens antigas ainda estão presentes, mesmo se não eliminados no servidor (porque ele ainda está guardado na cache).
Por exemplo CTRL + SHIFT + DEL no Google Chrome para apagar a sua 'cache'.
Isto ajudou-me a usar este código depois de tentar muitas soluções puras e isto. parecia o único a trabalhar (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>
Note também que é amplamente difundido que muitas soluções dizem que você tem que digitar Header set ...
mas é Header add ...
. Espero que isto ajude alguém a ter os mesmos problemas há algumas horas como eu.
Para uma cópia / pasta bastante fácil para aplicações.net, escrevi isto para activar o CORS a partir de um global.ficheiro asax. Este código segue os conselhos dados na resposta atualmente aceita, refletindo qualquer origem que seja dada no pedido na resposta. Isto consegue efectivamente " * " sem o utilizar. A razão para isso é que ele permite vários outros recursos do CORS, incluindo a capacidade de enviar um AJAX XMLHttpRequest com o atributo "witcredentials" definido para "verdade".
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" , "*");
}
}
Uma abordagem mais flexível é usar as expressões do Apache 2.4. Você pode comparar com domínios, caminhos e quase todas as outras variáveis de pedido. Embora a resposta seja *
para todos, os únicos que recebem essa resposta são aqueles que cumprem os requisitos de qualquer maneira.
<IfModule mod_headers.c>
<If "%{HTTP:Host} =~ /\\byourdomain\\.example$/i">
Header set Access-Control-Allow-Origin "*"
</If>
</IfModule>
if( preg_match("/http:\/\/(.*?)\.yourdomain.example/", $_SERVER['HTTP_ORIGIN'], $matches )) {
$theMatch = $matches[0];
header('Access-Control-Allow-Origin: ' . $theMatch);
}
A resposta parece ser usar o cabeçalho mais de uma vez. Isto é, em vez de enviar {[11]
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
Em Apache, você pode fazer isso em um httpd.conf
<VirtualHost>
secção ou .htaccess
ficheiro 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 primeiro argumento.
protected void Application_BeginRequest(object sender, EventArgs e)
{
// enable CORS
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "https://www.youtube.com");
}