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

224
demandé sur Elnur Abdurrakhimov 2012-12-22 17:44:26

8 réponses

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.

196
répondu monsur 2017-04-14 17:56:29

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.

54
répondu DaveRandom 2017-05-23 11:55:09

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
12
répondu Pratap Koritala 2017-10-16 19:20:31

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'),
7
répondu Lars 2015-07-20 00:12:13

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)

1
répondu kanidrive 2017-11-18 22:58:01

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"
0
répondu Jack K 2018-04-24 20:00:57

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;
-1
répondu Rubenisme 2017-03-22 11:12:31