headers - falta la cabecera cors ''access-control-allow-origin'' ajax
Subdominios, puertos y protocolos de comodines Access-Control-Allow-Origin (9)
Estoy intentando habilitar CORS para todos los subdominios, puertos y protocolos.
Por ejemplo, quiero poder ejecutar una solicitud XHR desde http://sub.mywebsite.com:8080/ a https://www.mywebsite.com/ *
Por lo general, me gustaría habilitar la solicitud de coincidencia de orígenes (y limitada a):
//*.mywebsite.com:*/*
Al configurar Access-Control-Allow-Origin
en .htaccess, solo se trabajó lo siguiente:
SetEnvIf Origin "http(s)?://(.+/.)?domain/.com(:/d{1,5})?$" CRS=$0
Header always set Access-Control-Allow-Origin "%{CRS}e" env=CRS
Probé varias otras palabras clave sugeridas Agregar Header append
, Header set
, ninguna funcionó como se sugiere en muchas respuestas en SO, aunque no tengo idea si estas palabras clave están desactualizadas o no son válidas para nginx .
Aquí está mi solución completa:
SetEnvIf Origin "http(s)?://(.+/.)?domain/.com(:/d{1,5})?$" CRS=$0
Header always set Access-Control-Allow-Origin "%{CRS}e" env=CRS
Header merge Vary "Origin"
Header always set Access-Control-Allow-Methods "GET, POST"
Header always set Access-Control-Allow-Headers: *
# Cached for a day
Header always set Access-Control-Max-Age: 86400
RewriteEngine On
# Respond with 200OK for OPTIONS
RewriteCond %{REQUEST_METHOD} OPTIONS
RewriteRule ^(.*)$ $1 [R=200,L]
Basándome en la answer de DaveRandom, también estaba jugando y encontré una solución Apache ligeramente más simple que produce el mismo resultado ( Access-Control-Allow-Origin
está configurado para el protocolo específico actual + dominio + puerto dinámicamente) sin usar ninguna regla de reescritura:
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"
Y eso es.
Aquellos que deseen habilitar CORS en el dominio principal (por ejemplo, mywebsite.com) además de todos sus subdominios pueden simplemente reemplazar la expresión regular en la primera línea con esta:
^(https?://(?:.+/.)?mywebsite/.com(?::/d{1,5})?)$
.
Nota: para el cumplimiento de las especificaciones y el comportamiento de almacenamiento en caché correcto, SIEMPRE agregue el encabezado de respuesta Vary: Origin
para los recursos habilitados para CORS, incluso para solicitudes que no sean CORS y aquellas provenientes de un origen no permitido (vea el ejemplo por qué ).
Con un ligero cambio en la respuesta 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;
Estábamos teniendo problemas similares con Font Awesome en un dominio estático "sin cookies" cuando leíamos las fuentes del "dominio de cookies" (www.domain.tld) y esta publicación era nuestro héroe. Consulte aquí: ¿Cómo puedo solucionar el problema de la fuente web ''Falta el encabezado de respuesta del Intercambio de recursos de origen cruzado (CORS)''?
Para los tipos de copiar / pegar-r (y para dar algunos accesorios) junté esto de todas las contribuciones y lo agregué a la parte superior del archivo .htaccess de la raíz del sitio:
<IfModule mod_headers.c> <IfModule mod_rewrite.c> 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" </IfModule> </IfModule>
Súper seguro, super elegante. Me encanta: no tiene que abrir el ancho de banda de sus servidores a los tipos de ladrones de recursos / hot-link-er.
Puntales para: @Noyo @DaveRandom @ pratap-koritala
(Traté de dejar esto como un comentario a la respuesta aceptada, pero todavía no puedo hacer eso)
Estoy respondiendo esta pregunta, porque la respuesta aceptada no puede coincidir con el dominio principal y solo funciona para el subdominio. Además, la agrupación de expresiones regulares es un éxito de rendimiento , que no es necesario.
Por ejemplo: no enviará encabezados de CORS para http://mywebsite.com mientras 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 habilitar su sitio, simplemente coloque su sitio en lugar de "mywebsite.com" en la Configuración de Apache anterior.
Para permitir múltiples sitios:
SetEnvIf Origin "http(s)?://(.+/.)?(othersite/.com|mywebsite/.com)(:/d{1,5})?$" CORS=$0
Pruebas después de la implementación:
La siguiente respuesta de rizo debe tener el encabezado "Access-Control-Allow-Origin" después del cambio.
curl -X GET -H "Origin: http://examplesite1.com" --verbose http://examplesite2.com/query
La especificación CORS es todo o nada. Solo admite *
, null
o el protocolo exacto + dominio + puerto: http://www.w3.org/TR/cors/#access-control-allow-origin-response-header
Su servidor tendrá que validar el encabezado de origen utilizando la expresión regular, y luego podrá repetir el valor de origen en el encabezado de respuesta de Control-Permitir-Autorizar.
Necesitaba una solución solo para PHP, así que en caso de que alguien también la necesite. Toma una cadena de entrada permitida como "* .example.com" y devuelve el nombre del servidor de encabezado de solicitud, si la entrada coincide.
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;
}
Y aquí están los casos de prueba para un proveedor de datos phpunit:
// <description> <allowed> <input> <expected>
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'', ''a.b.example.com'', ''a.b.example.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''),
Parece que la respuesta original fue para pre Apache 2.4. No funciono para mí. Esto es lo que tuve que cambiar para que funcione en 2.4. Esto funcionará para cualquier profundidad de subdominio de yourcompany.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"
EDITAR : Use la solución de @ Noyo en lugar de esta. Es más simple, más claro y, probablemente, mucho más eficaz bajo carga.
¡RESPUESTA ORIGINAL DEJADA AQUÍ PARA FINES HISTÓRICOS SOLAMENTE!
Hice algo de juego con este problema y se me ocurrió esta solución reutilizable .htaccess (o httpd.conf) que funciona con Apache:
<IfModule mod_rewrite.c>
<IfModule mod_headers.c>
# 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
</IfModule>
</IfModule>
Simplemente establezca la variable ACCESS_CONTROL_ROOT
en la parte superior del bloque en su dominio raíz y devolverá el valor del encabezado Origin:
solicitud al cliente en el valor del encabezado de respuesta Access-Control-Allow-Origin:
si coincide con su dominio.
Tenga en cuenta también que puede usar sub.mydomain.com
como ACCESS_CONTROL_ROOT
y limitará los orígenes a sub.mydomain.com
y *.sub.mydomain.com
(es decir, no tiene que ser la raíz del dominio). Los elementos que pueden variar (protocolo, puerto) pueden controlarse modificando la parte coincidente de URI de la expresión regular.