Subdomínios, portas e protocolos do Access-Control-Allow-Origin Wildcard

Estou tentando ativar o CORS para todos os subdomínios, portas e protocolo.

Por exemplo, eu quero ser capaz de executar uma solicitação de XHR de http://sub.mywebsite.com:8080/ para https://www.mywebsite.com/ *

Normalmente, gostaria de ativar a solicitação de origens correspondentes (e limitadas a):

//*.mywebsite.com:*/*

Com base na resposta da DaveRandom, eu também estava brincando e encontrei uma solução Apache um pouco mais simples que produz o mesmo resultado ( Access-Control-Allow-Origin é definido como o protocolo específico + domínio + porta dinamicamente) sem usar regras de reescrita:

 SetEnvIf Origin ^(https?://.+\.mywebsite\.com(?::\d{1,5})?)$ CORS_ALLOW_ORIGIN=$1 Header append Access-Control-Allow-Origin %{CORS_ALLOW_ORIGIN}e env=CORS_ALLOW_ORIGIN Header merge Vary "Origin" 

E é isso.

Aqueles que desejam ativar o CORS no domínio pai (por exemplo, mywebsite.com) além de todos os seus subdomínios podem simplesmente replace a expressão regular na primeira linha por esta:

^(https?://(?:.+\.)?mywebsite\.com(?::\d{1,5})?)$ .

Nota: Para conformidade com especificações e comportamento correto de armazenamento em cache, SEMPRE adicione o header de resposta Vary: Origin para resources ativados para CORS, mesmo para solicitações não CORS e aquelas de uma origem não permitida (veja o exemplo ).

A especificação CORS é tudo ou nada. Ele suporta apenas * , null ou o protocolo exato + domínio + porta: http://www.w3.org/TR/cors/#access-control-allow-origin-response-header

Seu servidor precisará validar o header de origem usando o regex e, em seguida, você pode ecoar o valor de origem no header de resposta Access-Control-Allow-Origin.

EDIT : Use a solução do @ Noyo em vez deste. É mais simples, mais claro e provavelmente muito mais produtivo sob carga.

RESPOSTA ORIGINAL DEIXADA AQUI PARA FINS HISTÓRICOS SOMENTE !!


Eu fiz algumas brincadeiras com este problema e surgiu com esta solução de .htaccess (ou httpd.conf) reutilizável que funciona com o Apache:

   # Define the root domain that is allowed SetEnvIf Origin .+ ACCESS_CONTROL_ROOT=yourdomain.com # Check that the Origin: matches the defined root domain and capture it in # an environment var if it does RewriteEngine On RewriteCond %{ENV:ACCESS_CONTROL_ROOT} !="" RewriteCond %{ENV:ACCESS_CONTROL_ORIGIN} ="" RewriteCond %{ENV:ACCESS_CONTROL_ROOT}&%{HTTP:Origin} ^([^&]+)&(https?://(?:.+?\.)?\1(?::\d{1,5})?)$ RewriteRule .* - [E=ACCESS_CONTROL_ORIGIN:%2] # Set the response header to the captured value if there was a match Header set Access-Control-Allow-Origin %{ACCESS_CONTROL_ORIGIN}e env=ACCESS_CONTROL_ORIGIN   

Basta definir a variável ACCESS_CONTROL_ROOT na parte superior do bloco para o seu domínio raiz e o valor do header de solicitação Origin: retornado ao cliente no valor do header de resposta Access-Control-Allow-Origin: response se corresponder ao seu domínio.

Observe também que você pode usar sub.mydomain.com como ACCESS_CONTROL_ROOT e limitará as origens a sub.mydomain.com e *.sub.mydomain.com (ou seja, não precisa ser a raiz do domínio). Os elementos que podem variar (protocolo, porta) podem ser controlados modificando a parte correspondente da URI da regex.

Estou respondendo a esta pergunta, porque a resposta aceita não pode coincidir com o domínio principal e só funciona para sub-domínio. Além disso, o agrupamento regex é um acerto de desempenho , o que não é necessário.

Por exemplo: ele não enviará headers de CORS para http://mywebsite.com enquanto funciona para http://somedomain.mywebsite.com/

 SetEnvIf Origin "http(s)?://(.+\.)?mywebsite\.com(:\d{1,5})?$" CORS=$0 Header set Access-Control-Allow-Origin "%{CORS}e" env=CORS Header merge Vary "Origin" 

Para ativar o seu site, basta colocar o site no lugar de “mywebsite.com” na Configuração do Apache acima.

Para permitir vários sites:

 SetEnvIf Origin "http(s)?://(.+\.)?(othersite\.com|mywebsite\.com)(:\d{1,5})?$" CORS=$0 

Teste após a implantação:

A seguinte resposta curl deve ter o header “Access-Control-Allow-Origin” após a alteração.

 curl -X GET -H "Origin: http://examplesite1.com" --verbose http://examplesite2.com/query 

Eu precisava de uma solução somente PHP, então apenas no caso de alguém precisar também. Ele recebe uma string de input permitida como “* .example.com” e retorna o nome do servidor de header da solicitação, se a input corresponder.

 function getCORSHeaderOrigin($allowed, $input) { if ($allowed == '*') { return '*'; } $allowed = preg_quote($allowed, '/'); if (($wildcardPos = strpos($allowed, '*')) !== false) { $allowed = str_replace('*', '(.*)', $allowed); } $regexp = '/^' . $allowed . '$/'; if (!preg_match($regexp, $input, $matches)) { return 'none'; } return $input; } 

E aqui estão os casos de teste para um provedor de dados phpunit:

 //     array('Allow Subdomain', 'www.example.com', 'www.example.com', 'www.example.com'), array('Disallow wrong Subdomain', 'www.example.com', 'ws.example.com', 'none'), array('Allow All', '*', 'ws.example.com', '*'), array('Allow Subdomain Wildcard', '*.example.com', 'ws.example.com', 'ws.example.com'), array('Disallow Wrong Subdomain no Wildcard', '*.example.com', 'example.com', 'none'), array('Allow Double Subdomain for Wildcard', '*.example.com', 'abexample.com', 'abexample.com'), array('Don\'t fall for incorrect position', '*.example.com', 'a.example.com.evil.com', 'none'), array('Allow Subdomain in the middle', 'a.*.example.com', 'a.bc.example.com', 'a.bc.example.com'), array('Disallow wrong Subdomain', 'a.*.example.com', 'b.bc.example.com', 'none'), array('Correctly handle dots in allowed', 'example.com', 'exampleXcom', 'none'), 

Estávamos tendo problemas semelhantes com o Font Awesome em um domínio “cookie-less” estático ao ler fonts do “domínio do cookie” (www.domain.tld) ​​e esse post era o nosso herói. Veja aqui: Como posso corrigir o problema de webfont ‘Cabeçalho de resposta de compartilhamento de resources de origem cruzada (CORS) ausente?

Para os tipos copy / paste-r (e para dar alguns adereços), juntei tudo de todas as contribuições e adicionei-o ao topo do arquivo .htaccess da raiz do site:

SetEnvIf Origin "http(s)?://(.+\.)?(othersite\.com|mywebsite\.com)(:\d{1,5})?$" CORS=$0 Header set Access-Control-Allow-Origin "%{CORS}e" env=CORS Header merge Vary "Origin"

Super Seguro, Super Elegante. Adoro: você não precisa abrir a largura de banda de seus servidores para tipos de ladrões de resources / hot-link-er.

Adereços para: @Noyo @DaveRandom @ pratap-koritala

(Eu tentei deixar isso como um comentário para a resposta aceita, mas eu não posso fazer isso ainda)

Parece que a resposta original foi para o pré Apache 2.4. Não funcionou para mim. Aqui está o que eu tive que mudar para que funcionasse no 2.4. Isso funcionará para qualquer profundidade de subdomínio de suaempresa.com .

 SetEnvIf Host ^((?:.+\.)*yourcompany\.com?)$ CORS_ALLOW_ORIGIN=$1 Header append Access-Control-Allow-Origin %{REQUEST_SCHEME}e://%{CORS_ALLOW_ORIGIN}e env=CORS_ALLOW_ORIGIN Header merge Vary "Origin" 

Com uma ligeira mudança na resposta de Lars.

 < ?php function validateOrigin($allowed, $input) { if ($allowed == '*') { return '*'; } $allowed = preg_quote($allowed, '/'); if (($wildcardPos = strpos($allowed, '\*')) !== false) { $allowed = str_replace('\*', '(.*)', $allowed); } $regexp = '/^' . $allowed . '$/'; if (!preg_match($regexp, $input, $matches)) { return 'none'; } return $input; } // CORS Preflight if($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { header('Access-Control-Allow-Origin: '.validateOrigin('https://*.domain.com', $_SERVER['HTTP_ORIGIN'])); header('X-Response-Code: 204', true, 204); header('Access-Control-Allow-Methods: GET'); header('Access-Control-Allow-Headers: Content-Type'); } elseif($_SERVER['REQUEST_METHOD'] === 'GET' && isset($_GET['VARIABLEHERE']) ) { // CODE HERE if($info["http_code"] === 200){ // 200 OK header('Content-type: application/json; charset=utf-8'); // CORS headers header('Access-Control-Allow-Origin: '.validateOrigin('https://*.domain.com', $_SERVER['HTTP_ORIGIN'])); echo $response; } else { header('X-Service-Response-Code: '.$info["http_code"], true, $info["http_code"]); } } else { // 400 bad request. header('X-Response-Code: 400', true, 400); } exit;