Sous-domaines, ports et protocoles du Joker Access-Control-Allow-Origin
j'essaie d'activer les CORS pour tous les sous-domaines, les ports et le protocole.
par exemple, je veux pouvoir exécuter une requête XHR à partir de http://sub.mywebsite.com:8080 / à https://www.mywebsite.com / *
typiquement, je voudrais activer la requête de correspondance des origines (et limitée à):
//*.mywebsite.com:*/*
8 réponses
basé sur la réponse de DaveRandom 151960920", je jouais aussi et j'ai trouvé une solution Apache légèrement plus simple qui produit le même résultat ( Access-Control-Allow-Origin
est défini au protocole spécifique + domaine + port dynamiquement) sans utiliser de règles de réécriture:
SetEnvIf Origin ^(https?://.+\.mywebsite\.com(?::\d{1,5})?)$ CORS_ALLOW_ORIGIN=
Header append Access-Control-Allow-Origin %{CORS_ALLOW_ORIGIN}e env=CORS_ALLOW_ORIGIN
Header merge Vary "Origin"
Et c'est tout.
ceux qui veulent activer CORS sur le domaine parent (par ex. mywebsite.com) en plus de tous ses sous-domaines peuvent simplement remplacer l'expression régulière dans la première ligne avec celui-ci:
^(https?://(?:.+\.)?mywebsite\.com(?::\d{1,5})?)$
.
Note: pour conformité aux spécifications et comportement de mise en cache correct, toujours ajouter l'en-tête de réponse Vary: Origin
pour les ressources activées par CORS, même pour les requêtes non-CORS et celles d'origine non-autorisée (voir exemple pourquoi ).
la spécification CORS est tout-ou-rien. Il soutient seulement *
, null
ou le protocole exact + domaine + port: http://www.w3.org/TR/cors/#access-control-allow-origin-response-header
votre serveur devra valider l'en-tête origin en utilisant le regex, et vous pourrez ensuite faire écho à la valeur origin dans l'en-tête de réponse Access-Control-Allow-Origin.
EDIT : utilisez la solution de @Noyo à la place de celle-ci. C'est plus simple, plus clair et probablement beaucoup plus performant sous la charge.
ORIGINAL ANSWER LEFT HERE FOR HISTORICAL PURPOSES ONLY!!
j'ai fait un peu de jeu autour de cette question et est venu avec cette réutilisables .htaccess (ou httpd.conf) solution qui fonctionne avec 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?://(?:.+?\.)?(?::\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>
vient de placer la variable ACCESS_CONTROL_ROOT
en haut du bloc dans votre domaine racine et elle fera écho à la valeur de l'en-tête de la requête Origin:
de nouveau au client dans la valeur de l'en-tête de la réponse Access-Control-Allow-Origin:
si elle correspond à votre domaine.
Notez aussi que vous pouvez utiliser sub.mydomain.com
comme ACCESS_CONTROL_ROOT
et qu'il limitera les origines à sub.mydomain.com
et *.sub.mydomain.com
(c.-à-d. qu'il ne doit pas être la racine du domaine). Les éléments qui sont autorisés à varier (protocole, port) peuvent être contrôlés en modifiant la partie URI matching de la regex.
je réponds à cette question, parce que le réponse acceptée ne peut pas correspondre au domaine primaire et ne fonctionne que pour le sous-domaine. En outre, regex grouping est une performance hit , qui n'est pas nécessaire.
par exemple: il n'enverra pas les en-têtes CORS pour http://mywebsite.com alors qu'il travaille pour http://somedomain.mywebsite.com/
SetEnvIf Origin "http(s)?://(.+\.)?mywebsite\.com(:\d{1,5})?$" CORS="151900920"
Header set Access-Control-Allow-Origin "%{CORS}e" env=CORS
Header merge Vary "Origin"
pour activer pour votre site, vous venez de mettre votre site à la place de "mywebsite.com" dans la Configuration Apache ci-dessus.
pour permettre plusieurs sites:
SetEnvIf Origin "http(s)?://(.+\.)?(othersite\.com|mywebsite\.com)(:\d{1,5})?$" CORS="151910920"
essai après déploiement:
la réponse curl suivante doit avoir l'en-tête" Access-Control-Allow-Origin " après le changement.
curl -X GET -H "Origin: http://examplesite1.com" --verbose http://examplesite2.com/query
j'avais besoin d'une solution PHP seulement, donc juste au cas où quelqu'un en aurait besoin aussi. Il faut une chaîne de caractères autorisée comme"*".example.com " et renvoie le nom du serveur d'en-tête de requête, si l'entrée correspond.
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;
}
et voici les cas d'essai pour un fournisseur de données 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'),
nous avions des problèmes similaires avec Font Awesome sur un domaine statique" sans cookie "lors de la lecture de polices du" cookie domain " (www.domaine.tld) et ce post a été notre héros. Voir ici: Comment puis-je corriger la question webfont de L'en-tête de réponse 'Missing Cross-Origin Resource Sharing (CORS)?
pour les types copy / paste-r (et pour donner quelques accessoires) j'ai assemblé cela de toutes les contributions et l'ai ajouté au dessus de la .fichier htaccess de la à la racine du site:
<IfModule mod_headers.c>
<IfModule mod_rewrite.c>
SetEnvIf Origin "http(s)?://(.+\.)?(othersite\.com|mywebsite\.com)(:\d{1,5})?$" CORS="151900920"
Header set Access-Control-Allow-Origin "%{CORS}e" env=CORS
Header merge Vary "Origin"
</IfModule>
</IfModule>
Super Sûr, Super Élégant. Love it: vous n'avez pas à ouvrir vos serveurs bande passante pour les Voleurs de ressources / types de hot-link-er.
Props to:@Noyo @DaveRandom @pratap-koritala
(j'ai essayé de laisser ce commentaire à la réponse acceptée, mais je ne peux pas encore le faire)
il semble que la réponse originale était pour Pre Apache 2.4. Il ne fonctionne pas pour moi. Voici ce que j'ai dû changer pour que ça marche en 2.4. Cela fonctionnera pour n'importe quelle profondeur de sous-domaine de yourcompany.com .
SetEnvIf Host ^((?:.+\.)*yourcompany\.com?)$ CORS_ALLOW_ORIGIN=
Header append Access-Control-Allow-Origin %{REQUEST_SCHEME}e://%{CORS_ALLOW_ORIGIN}e env=CORS_ALLOW_ORIGIN
Header merge Vary "Origin"
avec un léger changement dans la réponse 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;