Access-Control-Allow-Origin Domaines d'origine multiples?


1049

Existe-t-il un moyen d'autoriser plusieurs domaines croisés à l'aide de l'en- Access-Control-Allow-Origintête?

Je connais le *, mais c'est trop ouvert. Je veux vraiment autoriser seulement quelques domaines.

Par exemple, quelque chose comme ceci:

Access-Control-Allow-Origin: http://domain1.example, http://domain2.example

J'ai essayé le code ci-dessus mais il ne semble pas fonctionner dans Firefox.

Est-il possible de spécifier plusieurs domaines ou suis-je coincé avec un seul?



3
En utilisant le plus récent Firefox, ni les domaines séparés par des virgules, ni les espaces séparés par des espaces ne fonctionnaient. Faire correspondre une liste de domaines et mettre un seul hôte dans les en-têtes est toujours une meilleure sécurité et fonctionne correctement.
Daniel W.

1
Si vous rencontrez des difficultés avec HTTPS, j'ai trouvé une solution .
Alex W

7
note importante : autoriser uniquement les domaines cretain dans l'en-Access-Control-Allow-Origintête nesignifie pas que d'autres domaines ne peuvent pas déclencher une méthode sur ce noeud final (par exemple la méthode API REST). Cela signifie simplement que les origines non autorisées ne peuvent pas utiliser le résultat en javascript (le navigateur le garantit). Pour restreindre l'accès à un point de terminaison pour des domaines spécifiques, utilisez un filtre de requête côté serveur qui, par exemple, renvoie HTTP 401 pour les domaines non autorisés.
klues

1
Vous devez toujours ajouter un en- Vary: Origintête lorsque vous souhaitez utiliser plusieurs URL, voir: fetch.spec.whatwg.org/#cors-protocol-and-http-caches
Null

Réponses:


861

Cela ressemble à la façon recommandée de le faire est de demander à votre serveur de lire l'en-tête Origin du client, de le comparer à la liste des domaines que vous souhaitez autoriser, et s'il correspond, de Originrenvoyer la valeur de l'en- tête au client sous la forme l'en- Access-Control-Allow-Origintête dans la réponse.

Avec .htaccessvous pouvez le faire comme ceci:

# ----------------------------------------------------------------------
# Allow loading of external fonts
# ----------------------------------------------------------------------
<FilesMatch "\.(ttf|otf|eot|woff|woff2)$">
    <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>

41
Cela correspond à ce que suggère le W3C - w3.org/TR/cors/#access-control-allow-origin-response-hea
Simon B.

153
Mon problème avec cette réponse est qu'elle ne m'aide pas vraiment, car nous utilisons un CDN, et évidemment nous ne pouvons pas contrôler la façon dont le CDN définit les en-têtes par programme.
BT

6
Exemple réel (Nginx) dans ma réponse ci-dessous - stackoverflow.com/a/12414239/6084
mjallday

71
Si les caches ou les CDN sont un problème, utilisez l'en- tête Vary pour indiquer au cache / CDN de conserver des réponses distinctes pour différentes valeurs d'en-tête de demande d'origine. Vous incluriez un en-tête comme "Vary: Origin" dans votre réponse. Le cache / CDN sait alors qu'il doit envoyer une réponse à une demande avec en-tête "Origin: foo.example.com ", et une réponse différente à une demande avec en-tête "Origin: bar.example.com ".
Sean

10
@saturdayplace, si vous avez accès à l'en-tête Origin, vous avez dépassé CORS.
Paul Draper

222

Une autre solution que j'utilise en 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");
}

12
Pourquoi ne pas utiliser l'approche suggérée dans stackoverflow.com/a/1850482/11635 [et ne pas envoyer de caractère générique, juste l'origine demandée]? C'est juste plus permissif sans rien réaliser de plus?
Ruben Bartelink

15
ayant header('Access-Control-Allow-Origin: *')parfois dit ne peut pas utiliser de joker si le drapeau des informations d'identification est vrai - se produit quand header('Access-Control-Allow-Credentials: true')probablement. Donc, mieux vaut Allow-Origin le $http_originlui-même si les conditions sont remplies
Rakib

6
remplacer la dernière ligne avec header("Access-Control-Allow-Origin: " . $http_origin);pour le faire fonctionner
François Romain

2
Ce code semble défectueux, en ce sens que si aucun en-tête HTTP_ORIGIN n'est reconnu, aucun Access-Control-Allow-Origin n'est défini du tout, laissant le script grand ouvert.
Stephen R

9
@StephenR en fait "large fermé" serait plus précis, car le but de ceci est d'ouvrir le script à d'autres domaines;)
Kaddath

113

Cela a fonctionné pour moi:

SetEnvIf Origin "^http(s)?://(.+\.)?(domain\.example|domain2\.example)$" origin_is=$0 
Header always set Access-Control-Allow-Origin %{origin_is}e env=origin_is

Une fois installé .htaccess, cela fonctionnera à coup sûr.


24
meilleure solution pour moi, mais j'ai ajouté la prise en charge des ports (par exemple, localhost: 3000 pour le développement): SetEnvIf Origin "^ http (s)?: // (. + \.)? (localhost | stackoverflow.com | example1.com) ( : [0-9] +)? $ "Origin_is = $ 0
vszurma

2
Parmi les nombreuses réponses tout autour de stackoverflow, c'est celle qui a fonctionné.
Meetai.com

Je devais ajouter Header set Access-Control-Allow-Credentials truepour que cela fonctionne comme la réponse de @George
99 Problems - Syntax is not one

Cela fonctionne à coup sûr lorsque j'utilise Origin. Mais dans certains cas, Origin n'est pas disponible dans certaines demandes et il est également spécifique au navigateur. Ensuite, j'ai décidé d'utiliser Refererau lieu de Origin. Utilisation de RefererWorks, mais le problème est qu'il redéfinit l'URL complète sur Access-Control-Allow-OriginJe veux couper le nom de domaine Refereret l'attribuer Access-Control-Allow-Origin. Quelque chose comme le résultat de cette echo http://example.com/index.php/ab/cd | cut -d'/' -f1,2,3commande - dans bash. Est-il possible de faire de même dans le fichier conf (apache)? Une idée?
3AK

1
Ça ne marche pas pour moi. Toujours avoir une erreur de code 500 lorsque j'ajoute les 2 lignes. Actuellement en utilisant PHP 5.6.15
BoCyrill

91

J'ai eu le même problème avec les polices woff, plusieurs sous-domaines devaient y avoir accès. Pour autoriser les sous-domaines, j'ai ajouté quelque chose comme ça à mon httpd.conf:

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>

Pour plusieurs domaines, vous pouvez simplement modifier l'expression régulière dans SetEnvIf .


4
A fait l'affaire. Assurez-vous simplement d'adapter correctement l'expression régulière. J'avais besoin d'ajouter un point d'interrogation pour autoriser le domaine lui-même, par exemple (.*\.?example\.org)pour example.comet sub.example.com.
trkoch

3
Avez-vous des idées sur la façon d'adapter cela pour IIS 7?
Mark

N'est-ce pas contraire au but? Qu'est-ce qui empêcherait un utilisateur malveillant de falsifier la valeur d'en-tête Origin?
Grégory Joseph

1
@ GrégoryJoseph Access-Control-Allow-Origin ne consiste pas à cacher des ressources à quelqu'un qui peut en faire la demande. Il s'agit d'empêcher un site malveillant d'avoir des utilisateurs finaux qui appellent votre site. Dans le cas des fichiers de polices, cela ne peut que limiter efficacement le lien à chaud des polices, pourquoi elles (mozilla / firefox) n'ont pas fait la même chose pour d'autres ressources (js, css, etc.) me dépasse.
Tracker1

@trkoch, il y a un bug dans votre regex, il le permettra aussi subexample.com. Vous devriez le changer en:((.*\.)?example\.org)
bluesmoon

65

Voici comment renvoyer l'en-tête Origin s'il correspond à votre domaine avec Nginx, cela est utile si vous souhaitez servir une police à plusieurs sous-domaines:

location /fonts {
    # this will echo back the origin header
    if ($http_origin ~ "example.org$") {
        add_header "Access-Control-Allow-Origin" $http_origin;
    }
}

Je ne comprends pas en quoi est-ce différent de: add_header Access-Control-Allow-Origin *; Soin d'expliquer?
Anoyz

cela va retourner un en-tête qui autorise le navigateur à envoyer uniquement des demandes du domaine spécifié. si je suppose que je dirais que le navigateur pourrait autoriser le contenu d'un autre domaine chargé sur cette page pour accéder au serveur autrement.
mjallday

7
@Anoyz pour une chose, il peut y avoir une sécurité renforcée où "Allow *" n'est pas autorisé, mais un nom d'hôte spécifié et correspondant pour l'en-tête allow fonctionne. Un exemple ici, si vous voulez envoyer des informations d'autorisation entre domaines, vous ne pouvez pas utiliser "Allow *"
TCC

3
Est-ce que .dans example.org est interprété comme une valeur car il s'agit d'une expression régulière? Dans ce cas, cela autoriserait-il par erreur un TLD d'exemple-org personnalisé?
stuckj

1
Un regex correct devrait être "^example\.org$"parce que vous devez vous assurer qu'un pirate ne peut pas passer à travers votre regex avec subdomainexample.org(utiliser ^) ou example.orgevil(utiliser $) ou examplezorg(échapper \.)
zeg

27

Voici ce que j'ai fait pour une application PHP demandée par 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);
}

Si l'origine de la demande est autorisée par mon serveur, retournez le $http_originlui - même comme valeur de l'en- Access-Control-Allow-Origintête au lieu de renvoyer un *caractère générique.


20

Il y a un inconvénient dont vous devez être conscient: dès que vous externalisez des fichiers vers un CDN (ou tout autre serveur qui n'autorise pas les scripts) ou si vos fichiers sont mis en cache sur un proxy, la modification de la réponse en fonction de 'Origin' l'en-tête de la demande ne fonctionnera pas.


4
Pourriez-vous nous en dire plus, ou nous indiquer où nous pouvons chercher plus d'informations? C'est ce que je cherche à faire avec Limelight, et j'espère que vous vous trompez. L'un de nos techniciens a déclaré que tant que notre serveur de départ CDN enverrait l'en-tête, le CDN lui-même l'enverrait. Je n'ai pas encore testé
BT

12
Si les caches ou les CDN sont un problème, utilisez l'en-tête Vary pour indiquer au cache / CDN de conserver des réponses distinctes pour différentes valeurs d'en-tête de demande d'origine. Vous incluriez un en-tête comme "Vary: Origin" dans votre réponse. Le cache / CDN sait alors qu'il doit envoyer une réponse à une demande avec en-tête "Origin: foo.example.com ", et une réponse différente à une demande avec en-tête "Origin: bar.example.com ".
Sean

Vary: Origin n'est pas pris en charge par Akamai , l'un des plus grands CDN sur le marché ... Plus de détails disponibles ici également
Brad Parks

20

Pour plusieurs domaines, dans votre .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>

4
Cet extrait fonctionne parfaitement pour moi. Mais je ne comprends pas ce que ça fait: D
Karl Adler

2
cela a fonctionné pour moi, même si j'ai dû ajouter un '^' c'est-à-dire ... SetEnvIf Origin "^ http (s)?: // (www \.)?
gypsyDev

Il fait à peu près la même chose que stackoverflow.com/a/14034228/209139 . C'est juste que la syntaxe .htaccess est beaucoup plus difficile à lire que PHP. Header set Vary Originserait un bon ajout à cette réponse.
TRiG

1
Merci beaucoup pour votre aide
Cool Perfectionist

2
Je devais changer AccessControlAllowOrigin=$0$1à AccessControlAllowOrigin=$0. Sinon, cela n'a pas fonctionné pour les origines HTTPS. http://example.comest sorti correctement, maishttps://example.com est sorti comme https://example.coms, avec un supplément sà la fin.
TRiG

17

Pour que les utilisateurs de Nginx autorisent CORS pour plusieurs domaines. J'aime l'exemple de @ marshall bien que ses réponses ne correspondent qu'à un seul domaine. Pour faire correspondre une liste de domaines et de sous-domaines, cette expression régulière facilite le travail avec les polices:

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";
   }
}

Cela ne fera écho qu'aux en-têtes "Access-Control-Allow-Origin" qui correspondent à la liste de domaines donnée.


Pensez que vous devez verrouiller cette expression régulière à la fin avec \ z car sinon domain3.com.badhacker.com serait autorisé à accéder.
dft

@dft Nous définissons $ à la fin, ce qui fait cela
Adriano Rosa

Désolé, je voulais dire dans l'exemple essentiel, le message réel de @AdrianoRosa fait la même chose que \ z
dft


13

Voici une solution pour l'application Web Java, basée sur la réponse de yesthatguy.

J'utilise Jersey REST 1.x

Configurez le web.xml pour connaître Jersey REST et 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>

Voici le code de 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;
}

}

Le lien ci-dessus a expiré, pouvez-vous en ajouter un nouveau ou mettre à jour la réponse avec plus de détails, merci
RajKumar Samala

J'ai ajouté plus de détails, j'espère que cela vous aidera
duvo

12

Comme mentionné ci-dessus, Access-Control-Allow-Origindoit être unique et Varydoit être défini sur Originsi vous êtes derrière un CDN (Content Delivery Network).

Partie pertinente de ma configuration 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';
}

a set $corsune sorte de sens caché, ou est-ce juste spécifique à votre conifg? il semble qu'il puisse être omis avec le secondif
mikezter

C'est vrai, cela peut être omis si c'est la seule condition que vous testez pour définir les en-têtes, j'en avais plusieurs dans ma config.
hernvnc

9

Peut-être que je me trompe, mais autant que je puisse voir Access-Control-Allow-Origina un "origin-list"paramètre as.

Par définition, an origin-listest:

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

Et d'après cela, je soutiens que différentes origines sont admises et devraient être séparées par des espaces .


2
Cela semble être une interprétation correcte de la spécification; Cela dit, la spécification ne semble pas être entièrement prise en charge par les navigateurs actuels (par exemple, je viens de tester cela sur Firefox 17.0 et j'ai confirmé que cela ne fonctionnerait pas).
Rick Riensche

7
La section de spécification CORS5.1 Access-Control-Allow-Origin Response Header indique que la liste d'origine est contrainte: Plutôt que d'autoriser une liste d'origine séparée par des espaces, il s'agit soit d'une seule origine, soit de la chaîne "null".
maxpolk

2
Comme je l'ai mentionné dans un commentaire sur ma propre réponse, cela fait partie d'une note de mise en œuvre, pas une exigence RFC 2119. La réponse «correcte» consiste absolument à utiliser des valeurs délimitées par des espaces. Le problème est simplement que les implémentations sont incomplètes et donc la réponse «correcte» ne fonctionne pas nécessairement. Cela devrait, mais ce n'est pas le cas. Cependant, à l'avenir, à mesure que les implémentations s'amélioreront, cela pourrait changer.
Bob Aman

8

Pour les applications ExpressJS, vous pouvez utiliser:

app.use((req, res, next) => {
    const corsWhitelist = [
        'https://domain1.example',
        'https://domain2.example',
        'https://domain3.example'
    ];
    if (corsWhitelist.indexOf(req.headers.origin) !== -1) {
        res.header('Access-Control-Allow-Origin', req.headers.origin);
        res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
    }

    next();
});

cela permettra à tous les autres appels par un prochain appel ...
Ievgen Naida

@IevgenNaida Alors? Quel est le problème?
eyecatchUp

7

J'ai eu du mal à configurer cela pour un domaine exécutant HTTPS, alors j'ai pensé que je partagerais la solution. J'ai utilisé la directive suivante dans mon fichier httpd.conf :

    <FilesMatch "\.(ttf|otf|eot|woff)$">
            SetEnvIf Origin "^http(s)?://(.+\.)?example\.com$" AccessControlAllowOrigin=$0
            Header set Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin
    </FilesMatch>

Changez example.compour votre nom de domaine. Ajoutez-le à l'intérieur <VirtualHost x.x.x.x:xx>de votre fichier httpd.conf . Notez que si vous avez VirtualHostun suffixe de port (par exemple :80), cette directive ne s'appliquera pas à HTTPS, vous devrez donc également aller dans / etc / apache2 / sites-available / default-ssl et ajouter la même directive dans ce fichier, à l'intérieur du<VirtualHost _default_:443> section.

Une fois les fichiers de configuration mis à jour, vous devrez exécuter les commandes suivantes dans le terminal:

a2enmod headers
sudo service apache2 reload

J'aime cette option et l'ai combinée / modifiée avec l'implémentation de @George. Parfois, les serveurs n'ont pas a2enmod disponible, donc tout ce que vous avez à faire est de vérifier votre httpd.conf principal pour voir si la ligne: LoadModule headers_module modules / mod_headers.so n'est pas commentée.
Mike Kormendy

Mon origine avait un numéro de port, j'ai donc modifié l'expression régulière pour inclure cela: ^http(s)?://(.+\.)?example\.com(:\d+)?$
indiv

5

Si vous rencontrez des problèmes avec les polices, utilisez:

<FilesMatch "\.(ttf|ttc|otf|eot|woff)$">
    <IfModule mod_headers>
        Header set Access-Control-Allow-Origin "*"
    </IfModule>
</FilesMatch>

3

Une approche plus flexible consiste à utiliser les expressions d'Apache 2.4. Vous pouvez faire correspondre des domaines, des chemins et à peu près toutes les autres variables de demande. Bien que la réponse envoyée soit toujours *, les seuls demandeurs qui la reçoivent sont de toute façon ceux qui répondent aux exigences. L'utilisation de l' Originen-tête de demande (ou de tout autre) dans l'expression entraîne la fusion automatique d'Apache dans l'en- Varytête de réponse, afin que la réponse ne soit pas réutilisée pour une origine différente.

<IfModule mod_headers.c>
    <If "%{HTTP:Host} =~ /\\bcdndomain\\.example$/i && %{HTTP:Origin} =~ /\\bmaindomain\\.example$/i">
        Header set Access-Control-Allow-Origin "*"
    </If>
</IfModule>

2
Je suis venu ici parce que certains navigateurs n'acceptent pas les *informations d'identification comme la connexion. Il sera donc préférable de passer le nom d'hôte correspondant au lieu de *.
KeitelDOG

@KeitelDOG comment capturer dynamiquement l'origine correcte et la renvoyer lorsqu'il y a plusieurs origines, au lieu de répéter le code pour chaque domaine? On dirait qu'il pourrait être possible avec des expressions , mais les documents ne sont pas claires pour moi.
Walf

En fait, mon vrai problème était que laravel n'a pas renvoyé l'en- Access-Control-Allow-Origintête pour la OPTIONSdemande de contrôle en amont qui vérifie les en-têtes pour voir si le serveur autorise cette origine. Je l'ai réparé. Ce *n'était donc pas le vrai problème pour moi. Mais, certains navigateurs n'acceptent toujours pas les *informations d'identification, donc lorsqu'une application Web envoie une demande d'origine croisée, ils DOIVENT spécifier un en- HTTP_ORIGINtête auquel vous pourriez accéder dynamiquement avec une variable Origindans .htaccessApache ou $_SERVER['HTTP_ORIGIN'];PHP. Quoi qu'il en soit, votre solution est bonne car elle autorise toutes les origines, mais moins sécurisée
KeitelDOG

Mais 2 choses à retenir, c'est que 1) Fournir *permet tout. 2) HOST est différent de ORIGIN. HOST est le «TARGET HOST» qui est transmis à l'en-tête de la demande. Mais ORIGIN est celui INITIAL HOSTqui envoie la demande au TARGET HOST. Par conséquent, dans votre code, ORIGIN HOSTest ignoré et n'est jamais utilisé. Voir les réponses ci-dessus et vous verrez comment ils utilisent des ORIGINvaleurs pour les ajouter Access-Control-Allow-Origin.
KeitelDOG

@KeitelDOG N'autorise *pas tout le monde car l'utilisation de l'en- Origintête de demande dans l'expression fait que Apache le fusionne automatiquement dans l'en- Varytête de réponse, sauf si l'on utilise req_novary('Origin')(probablement indésirable). Les navigateurs savent qu'ils peuvent obtenir une réponse différente pour un autre Originet si la valeur envoyée ne réussit pas son test, l'en- Access-Control-Allow-Origintête n'est jamais défini.
Walf

3

Code PHP:

$httpOrigin = isset($_SERVER['HTTP_ORIGIN']) ? $_SERVER['HTTP_ORIGIN'] : null;
if (in_array($httpOrigin, [
    'http://localhost:9000', // Co-worker dev-server
    'http://127.0.0.1:9001', // My dev-server
])) header("Access-Control-Allow-Origin: ${httpOrigin}");
header('Access-Control-Allow-Credentials: true');

2

HTTP_ORIGIN n'est pas utilisé par tous les navigateurs. HTTP_ORIGIN est-il sécurisé? Pour moi ça revient vide en FF.
J'ai les sites auxquels j'autorise l'accès à mon site envoyer un ID de site, je vérifie ensuite ma base de données pour l'enregistrement avec cet ID et obtenir la valeur de la colonne SITE_URL (www.votresite.com).

header('Access-Control-Allow-Origin: http://'.$row['SITE_URL']);

Même si l'envoi via un ID de site valide, la demande doit provenir du domaine répertorié dans ma base de données associé à cet ID de site.


2

Voici une option étendue pour apache qui inclut certaines des définitions de police les plus récentes et prévues:

<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>

2

Pour faciliter l'accès à plusieurs domaines pour un service ASMX, j'ai créé cette fonction dans le fichier global.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();
    }
}

Cela permet OPTIONSégalement la gestion CORS du verbe.


2

Exemple de code PHP pour faire correspondre les sous-domaines.

if( preg_match("/http:\/\/(.*?)\.yourdomain.example/", $_SERVER['HTTP_ORIGIN'], $matches )) {
        $theMatch = $matches[0];
        header('Access-Control-Allow-Origin: ' . $theMatch);
}

2

Pour un copier / coller assez facile pour les applications .NET, j'ai écrit ceci pour activer CORS à partir d'un global.asaxfichier. Ce code suit les conseils donnés dans la réponse actuellement acceptée, reflétant toute origine renvoyée dans la demande dans la réponse. Cela permet effectivement d'atteindre «*» sans l'utiliser.

La raison en est qu'il permet plusieurs autres fonctionnalités CORS , y compris la possibilité d'envoyer un AJAX XMLHttpRequest avec l'attribut 'withCredentials' défini sur 'true'.

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" , "*");
    }
}

1

Et une autre réponse dans Django. Pour qu'une vue unique autorise CORS à partir de plusieurs domaines, voici mon code:

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

1

Passerelle AWS Lambda / API

Pour plus d'informations sur la configuration de plusieurs origines sur AWS Lambda sans serveur et la passerelle API - bien qu'une solution assez importante pour quelque chose que vous ressentez devrait être assez simple - voir ici:

https://stackoverflow.com/a/41708323/1624933


Il n'est actuellement pas possible de configurer plusieurs origines dans API Gateway, voir ici: https://docs.aws.amazon.com/apigateway/latest/developerguide/how-to-cors-console.html ), mais la recommandation (dans la réponse ci-dessus) est:

  • inspecter l'en-tête Origin envoyé par le navigateur
  • vérifier par rapport à une liste blanche des origines
  • s'il correspond, renvoyez l'origine entrante comme en-tête Access-Control-Allow-Origin, sinon retournez un espace réservé (origine par défaut).

La solution simple est évidemment d'activer TOUS (*) comme ceci:

exports.handler = async (event) => {
    const response = {
        statusCode: 200,
        headers: {
            "Access-Control-Allow-Origin": "*",
            "Access-Control-Allow-Credentials" : true // Required for cookies, authorization headers with HTTPS
        },
        body: JSON.stringify([{

Mais il pourrait être préférable de le faire du côté de la passerelle API (voir le deuxième lien ci-dessus).


2
Access-Control-Allow-Credentials: truen'est pas autorisé avec un caractère générique Access-Control-Allow-Origin: *. Définissez un spécifique à la <origin>place.
Tom

@ Tom, oui, je ne sais pas pourquoi c'était là, je ne me souviens pas, mais je pourrais l'avoir copié à partir des valeurs par défaut qui ont été ajoutées sur AWS? Merci de l'avoir souligné.
timhc22

0

La réponse du support de Google sur la diffusion d'annonces via SSL et la grammaire du RFC lui - même semblent indiquer que vous pouvez délimiter les URL. Je ne sais pas à quel point cela est bien pris en charge dans différents navigateurs.


" diffuser des annonces via ssl" renvoie à la spécification w3.org/TR/cors/#access-control-allow-origin-response-header qui ajoute une note: "Dans la pratique, la production d'origine-liste-ou-nulle est plus contrainte Plutôt que d'autoriser une liste d'origines séparées par des espaces, il s'agit soit d'une seule origine, soit de la chaîne "null".
spazm

Bien qu'il soit important de noter ce détail, lorsqu'une spécification indique "En pratique", cela ne signifie pas qu'elle est uniquement valable pour le faire de cette façon. Cela signifie que si vous le faites de cette façon, vous pouvez rencontrer des problèmes car la majorité des implémenteurs implémentent la spécification de manière incorrecte ou incomplète. La spécification permet une liste d'origines séparées par des espaces, que vous pouvez voir ici dans l'EBNF sous origin-list: tools.ietf.org/html/rfc6454#section-7.1
Bob Aman

0

Si vous essayez autant d'exemples de code comme moi pour le faire fonctionner en utilisant CORS, il convient de mentionner que vous devez d'abord vider votre cache pour essayer s'il fonctionne réellement, semblable à des problèmes comme lorsque de vieilles images sont toujours présentes, même si c'est supprimé sur le serveur (car il est toujours enregistré dans votre cache).

Par exemple CTRL + SHIFT + DELdans Google Chrome pour supprimer votre cache.

Cela m'a aidé à utiliser ce code après avoir essayé de nombreuses .htaccesssolutions pures et cela semblait le seul qui fonctionnait (au moins pour moi):

    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>

Notez également qu'il est largement répandu que de nombreuses solutions disent que vous devez taper, Header set ...mais c'est le cas Header add .... J'espère que cela aide quelqu'un qui a les mêmes problèmes depuis quelques heures comme moi.


0

La réponse ci-dessous est spécifique à C #, mais le concept devrait être applicable à toutes les différentes plates-formes.

Pour autoriser les demandes d'origine croisée à partir d'une API Web, vous devez autoriser les demandes d'options à votre application et ajouter une annotation ci-dessous au niveau du contrôleur.

[EnableCors (UrlString, Header, Method)] Désormais, les origines ne peuvent être transmises que sous forme de chaîne. SO si vous souhaitez transmettre plusieurs URL dans la demande, transmettez-la en tant que valeur séparée par des virgules.

UrlString = " https: //a.hello.com,https: //b.hello.com "


0

Une seule origine peut être spécifiée pour l'en-tête Access-Control-Allow-Origin. Mais vous pouvez définir l'origine dans votre réponse en fonction de la demande. N'oubliez pas non plus de définir l'en-tête Vary. En PHP, je ferais ce qui suit:

    /**
     * Enable CORS for the passed origins.
     * Adds the Access-Control-Allow-Origin header to the response with the origin that matched the one in the request.
     * @param array $origins
     * @return string|null returns the matched origin or null
     */
    function allowOrigins($origins)
    {
        $val = $_SERVER['HTTP_ORIGIN'] ?? null;
        if (in_array($val, $origins, true)) {
            header('Access-Control-Allow-Origin: '.$val);
            header('Vary: Origin');

            return $val;
        }

        return null;
    }

  if (allowOrigins(['http://localhost', 'https://localhost'])) {
      echo your response here, e.g. token
  }

-2

Nous pouvons également définir cela dans le fichier Global.asax pour l'application Asp.net.

protected void Application_BeginRequest(object sender, EventArgs e)
    {

    // enable CORS
    HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "https://www.youtube.com");

    }
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.