Zugriffssteuerung-Zulassen-Ursprung Mehrere Ursprungsdomänen?


1049

Gibt es eine Möglichkeit, mehrere domänenübergreifende Funktionen mithilfe des Access-Control-Allow-OriginHeaders zuzulassen ?

Ich bin mir dessen bewusst *, aber es ist zu offen. Ich möchte wirklich nur ein paar Domains zulassen.

Zum Beispiel so etwas:

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

Ich habe den obigen Code ausprobiert, aber er scheint in Firefox nicht zu funktionieren.

Ist es möglich, mehrere Domains anzugeben, oder stecke ich nur bei einer fest?



3
Mit dem neuesten Firefox funktionierten weder durch Kommas getrennte noch durch Leerzeichen getrennte Domänen. Das Abgleichen mit einer Liste von Domänen und das Einfügen eines einzelnen Hosts in die Header ist immer noch sicherer und funktioniert ordnungsgemäß.
Daniel W.

1
Wenn Sie damit für HTTPS zu kämpfen haben, habe ich eine Lösung gefunden .
Alex W

7
Wichtiger Hinweis : Das Zulassen nur bestimmter Domänen imAccess-Control-Allow-OriginHeader bedeutet nicht , dass andere Domänen keine Methode auf diesem Endpunkt auslösen können (z. B. REST-API-Methode). Dies bedeutet lediglich, dass nicht zugelassene Ursprünge das Ergebnis nicht in Javascript verwenden können (der Browser stellt dies sicher). Verwenden Sie zum Einschränken des Zugriffs auf einen Endpunkt für bestimmte Domänen einen serverseitigen Anforderungsfilter, der z. B. HTTP 401 für nicht zulässige Domänen zurückgibt.
Klues

1
Sie sollten immer einen Vary: OriginHeader anhängen, wenn Sie mehrere URLs verwenden möchten, siehe: fetch.spec.whatwg.org/#cors-protocol-and-http-caches
Null

Antworten:


861

Klingt so, als würde empfohlen, dass Ihr Server den Origin-Header vom Client liest, diesen mit der Liste der Domänen vergleicht, die Sie zulassen möchten, und wenn dies übereinstimmt, den Wert des OriginHeaders an den Client zurücksendet der Access-Control-Allow-OriginHeader in der Antwort.

Mit .htaccesskönnen Sie es so machen:

# ----------------------------------------------------------------------
# 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
Dies entspricht den Vorschlägen
Simon B.

153
Mein Problem mit dieser Antwort ist, dass es mir nicht wirklich hilft, da wir ein CDN verwenden und offensichtlich nicht steuern können, wie das CDN Header programmgesteuert setzt.
BT

6
Aktuelles Beispiel (Nginx) in meiner Antwort unten - stackoverflow.com/a/12414239/6084
mjallday

71
Wenn Caches oder CDNs ein Problem darstellen, verwenden Sie den Vary-Header , um den Cache / CDN anzuweisen , separate Antworten für verschiedene Origin-Anforderungsheaderwerte zu speichern. Sie würden Ihrer Antwort einen Header wie "Variieren: Ursprung" hinzufügen. Der Cache / CDN weiß dann, dass er eine Antwort auf eine Anfrage mit dem Header "Origin: foo.example.com " und eine andere Antwort auf eine Anfrage mit dem Header "Origin: bar.example.com " senden soll .
Sean

10
@saturdayplace, wenn Sie Zugriff auf den Origin-Header haben, sind Sie hinter CORS.
Paul Draper

222

Eine andere Lösung, die ich in PHP verwende:

$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
Warum nicht den in stackoverflow.com/a/1850482/11635 vorgeschlagenen Ansatz verwenden [und keinen Platzhalter senden, nur den angeforderten Ursprung]? Dies ist nur freizügiger, ohne etwas mehr zu erreichen?
Ruben Bartelink

15
mit header('Access-Control-Allow-Origin: *')manchmal sagt nicht Platzhalter verwenden können , wenn Anmeldeinformationen Flag wahr ist - passiert , wenn header('Access-Control-Allow-Credentials: true')wahrscheinlich. Also, besser Allow-Origin das $http_originselbst, wenn die Bedingungen erfüllt sind
Rakib

6
Ersetzen Sie die letzte Zeile durch header("Access-Control-Allow-Origin: " . $http_origin);, damit es funktioniert
François Romain

2
Dieser Code scheint insofern fehlerhaft zu sein, als wenn kein HTTP_ORIGIN-Header erkannt wird, überhaupt kein Access-Control-Allow-Origin festgelegt wird, wodurch das Skript weit offen bleibt.
Stephen R

9
@StephenR tatsächlich "weit geschlossen" wäre genauer, da der Zweck davon ist, das Skript für andere Domänen zu öffnen;)
Kaddath

113

Das hat bei mir funktioniert:

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

Wenn .htaccesses eingesetzt wird, wird es sicher funktionieren.


24
beste Lösung für mich, aber ich habe Port-Unterstützung hinzugefügt (zB localhost: 3000 für die Entwicklung): SetEnvIf Origin "^ http (s) ?: // (. + \.)? (localhost | stackoverflow.com | example1.com) ( : [0-9] +)? $ "Origin_is = $ 0
vszurma

2
Von den verschiedenen Antworten rund um den Stackoverflow hat dies funktioniert.
Meetai.com

Ich musste hinzufügen, Header set Access-Control-Allow-Credentials truedamit dies wie die Antwort von @George funktioniert
99 Probleme - Die Syntax ist nicht eine am

Dies funktioniert sicher, wenn ich Origin verwende. In einigen Fällen ist Origin jedoch in einigen Anfragen nicht verfügbar und auch browserspezifisch. Dann entschied ich mich für Refereranstelle von Origin. Die Verwendung Refererfunktioniert, aber das Problem ist, dass die vollständige URL auf " Access-Control-Allow-OriginIch möchte den Domainnamen ausschneiden Refererund ihm zuweisen" zurückgesetzt wird Access-Control-Allow-Origin. So etwas wie das Ergebnis davon - echo http://example.com/index.php/ab/cd | cut -d'/' -f1,2,3in Bash-Befehl. Ist dies in der (apache) conf-Datei möglich? Irgendeine Idee?
3AK

1
Das funktioniert bei mir nicht. Immer einen Code 500-Fehler, wenn ich die 2 Zeilen hinzufüge. Tatsächlich mit PHP 5.6.15
BoCyrill

91

Ich hatte das gleiche Problem mit Woff-Schriften, mehrere Subdomains mussten Zugriff haben. Um Subdomains zuzulassen, habe ich meiner httpd.conf Folgendes hinzugefügt:

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>

Für mehrere Domains können Sie einfach den regulären Ausdruck in ändern SetEnvIf.


4
Hat den Trick gemacht. Stellen Sie einfach sicher, dass Sie den regulären Ausdruck richtig anpassen. Ich musste ein Fragezeichen hinzufügen, um die Domain selbst zuzulassen, z . B. (.*\.?example\.org)für example.comund sub.example.com.
Trkoch

3
Irgendwelche Gedanken darüber, wie dies für IIS 7 angepasst werden kann?
Mark

Ist das nicht ein Misserfolg des Zwecks? Was würde einen böswilligen Benutzer daran hindern, den Origin-Header-Wert zu fälschen?
Grégory Joseph

1
@ GrégoryJoseph Bei Access-Control-Allow-Origin geht es nicht darum, Ressourcen vor jemandem zu verstecken, der sie anfordern kann. Es geht darum zu verhindern, dass Endbenutzer auf einer böswilligen Website Ihre Website aufrufen. Im Fall von Schriftdateien kann dies nur das Hot-Linking von Schriftarten effektiv einschränken. Warum sie (Mozilla / Firefox) für andere Ressourcen (JS, CSS usw.) nicht dasselbe getan haben, ist mir ein Rätsel.
Tracker1

@trkoch, es gibt einen Fehler in Ihrer Regex, der es auch erlaubt subexample.com. Sie sollten es ändern in:((.*\.)?example\.org)
Bluesmoon

65

Hier erfahren Sie, wie Sie den Origin-Header wiedergeben, wenn er mit Ihrer Domain mit Nginx übereinstimmt. Dies ist nützlich, wenn Sie eine Schriftart für mehrere Subdomains bereitstellen möchten:

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

Ich kann nicht verstehen, wie sich das unterscheidet von: add_header Access-Control-Allow-Origin *; Möchtest du das erklären?
Anoyz

Dadurch wird ein Header zurückgegeben, der den Browser berechtigt, nur Anforderungen von der angegebenen Domäne zu senden. Wenn ich vermuten würde, würde ich sagen, dass der Browser Inhalte von einer anderen auf dieser Seite geladenen Domain autorisieren könnte, um auf den Server zuzugreifen.
Mittwoch,

7
@Anoyz Zum einen kann die Sicherheit erhöht werden, wenn "Zulassen *" nicht zulässig ist, aber ein angegebener und übereinstimmender Hostname für den zulässigen Header funktioniert. Ein Beispiel hier, wenn Sie Autorisierungsinformationen domänenübergreifend senden möchten, können Sie "Zulassen *"
TCC

3
Wird .in example.org als ein beliebiger Wert interpretiert, da dies ein regulärer Ausdruck ist? In welchem ​​Fall würde dies fälschlicherweise eine benutzerdefinierte TLD für Beispielorganisationen zulassen?
Stuckj

1
Eine korrekte Regex sollte sein, "^example\.org$"weil Sie sicherstellen müssen, dass ein Hacker nicht mit subdomainexample.org(Verwendung ^) oder example.orgevil(Verwendung $) oder examplezorg(Flucht \.) durch Ihre Regex schlüpfen kann
zeg

27

Folgendes habe ich für eine PHP-Anwendung getan, die von AJAX angefordert wird

$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);
}

Wenn der anfordernde Ursprung von meinem Server zugelassen wird, geben Sie sich $http_originselbst als Wert des Access-Control-Allow-OriginHeaders zurück, anstatt einen *Platzhalter zurückzugeben.


20

Es gibt einen Nachteil, den Sie beachten sollten: Sobald Sie Dateien an ein CDN (oder einen anderen Server, der keine Skripterstellung zulässt) auslagern oder wenn Ihre Dateien auf einem Proxy zwischengespeichert werden, ändern Sie die Antwort basierend auf "Origin". Anforderungsheader funktioniert nicht.


4
Könnten Sie dies näher erläutern oder uns auf eine Stelle verweisen, an der wir nach weiteren Informationen suchen können? Ich möchte genau das mit Limelight tun und hoffe, dass Sie sich irren. Einer unserer Techniker sagte, solange unser CDN-Seed-Server den Header sendet, wird er vom CDN selbst gesendet. Habe es noch nicht getestet
BT

12
Wenn Caches oder CDNs ein Problem darstellen, verwenden Sie den Vary-Header, um den Cache / CDN anzuweisen, separate Antworten für verschiedene Origin-Anforderungsheaderwerte zu speichern. Sie würden Ihrer Antwort einen Header wie "Variieren: Ursprung" hinzufügen. Der Cache / CDN weiß dann, dass er eine Antwort auf eine Anfrage mit dem Header "Origin: foo.example.com " und eine andere Antwort auf eine Anfrage mit dem Header "Origin: bar.example.com " senden soll .
Sean

Vary: Origin wird nicht von Akamai unterstützt , einem der größten CDNs da draußen ... Weitere Details finden Sie auch hier
Brad Parks

20

Für mehrere Domains in Ihrem .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
Dieses Snippet funktioniert perfekt für mich. Aber ich verstehe nicht, was es tut: D
Karl Adler

2
Dies funktionierte für mich, obwohl ich ein '^' hinzufügen musste, dh ... SetEnvIf Origin "^ http (s) ?: // (www \.)?
gypsyDev

Es funktioniert fast genauso wie stackoverflow.com/a/14034228/209139 . Es ist nur so, dass die .htaccess-Syntax viel schwieriger zu lesen ist als PHP. Header set Vary Originwäre eine schöne Ergänzung zu dieser Antwort.
TRiG

1
Vielen Dank für Ihre Hilfe
Cool Perfectionist

2
Ich musste ändern AccessControlAllowOrigin=$0$1zu AccessControlAllowOrigin=$0. Andernfalls funktionierte es nicht für HTTPS-Ursprünge. http://example.comkam richtig heraus, https://example.comkam aber heraus https://example.coms, mit einem Extra sam Ende.
TRiG

17

Für Nginx-Benutzer, CORS für mehrere Domänen zuzulassen. Ich mag das Beispiel von @ marshall, obwohl seine Antworten nur einer Domain entsprechen. Um eine Liste von Domänen und Unterdomänen abzugleichen, erleichtert diese Regex die Arbeit mit Schriftarten:

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

Dies gibt nur "Access-Control-Allow-Origin" -Header wieder, die mit der angegebenen Liste von Domains übereinstimmen.


Denken Sie, Sie müssen diesen regulären Ausdruck am Ende mit \ z sperren, da sonst domain3.com.badhacker.com Zugriff erhalten würde.
dft

@dft Wir definieren $ am Ende, was das tut
Adriano Rosa

Entschuldigung, ich meinte im Hauptbeispiel, dass der eigentliche Beitrag von @AdrianoRosa dasselbe tut wie \ z
dft


13

Hier ist eine Lösung für die Java-Web-App, basierend auf der Antwort von yesthatguy.

Ich benutze Jersey REST 1.x.

Konfigurieren Sie die Datei web.xml so, dass Jersey REST und CORSResponseFilter bekannt sind

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

Hier ist der Code für 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;
}

}

Der obige Link ist abgelaufen, können Sie einen neuen hinzufügen oder die Antwort mit weiteren Details aktualisieren. Danke
RajKumar Samala

Ich habe weitere Details hinzugefügt, hoffe das hilft
Duvo

12

Wie oben erwähnt, Access-Control-Allow-Originsollte eindeutig sein und Varyauf eingestellt werden, Originwenn Sie sich hinter einem CDN (Content Delivery Network) befinden.

Relevanter Teil meiner Nginx-Konfiguration:

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

hat set $corseine versteckte Bedeutung oder ist sie nur spezifisch für Ihr Conifg? es scheint, dass es zusammen mit dem zweitenif
mikezter

Das ist richtig, es kann weggelassen werden, wenn dies die einzige Bedingung ist, die Sie testen, um die Header festzulegen. Ich hatte mehrere in meiner Konfiguration.
Hernvnc

9

Vielleicht irre ich mich, aber soweit ich sehen kann Access-Control-Allow-Originhat ein "origin-list"as Parameter.

Durch die Definition eines origin-listist:

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

Und daraus argumentiere ich, dass unterschiedliche Ursprünge zugelassen sind und räumlich getrennt sein sollten .


2
Das scheint eine korrekte Interpretation der Spezifikation zu sein; Trotzdem scheint die Spezifikation von aktuellen Browsern nicht vollständig unterstützt zu werden (zum Beispiel habe ich dies gerade in Firefox 17.0 getestet und bestätigt, dass es nicht funktioniert).
Rick Riensche

7
Die CORS Spezifikationsabschnitt 5.1 Access-Control-Allow-Origin Response Headerbesagt , dass herkunfts Liste beschränkt ist: statt zuzulassen , dass eine durch Leerzeichen getrennte Liste von Ursprüngen, es ist entweder ein einzelner Ursprung oder die Zeichenkette „null“.
Maxpolk

2
Wie ich in einem Kommentar zu meiner eigenen Antwort erwähnt habe, ist dies Teil eines Implementierungshinweises und keine RFC 2119-Anforderung. Die 'richtige' Antwort ist absolut, durch Leerzeichen getrennte Werte zu verwenden. Das Problem ist einfach, dass die Implementierungen unvollständig sind und die "richtige" Antwort nicht unbedingt funktioniert. Es sollte, aber es tut nicht. In Zukunft kann sich dies jedoch ändern, wenn die Implementierungen besser werden.
Bob Aman

8

Für ExpressJS-Anwendungen können Sie Folgendes verwenden:

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();
});

Dies ermöglicht alle anderen Anrufe durch einen nächsten Anruf ...
Ievgen Naida

@ IevgenNaida Also? Was ist das Problem?
eyecatchUp

7

Ich hatte Mühe, dies für eine Domain einzurichten, auf der HTTPS ausgeführt wird, und dachte mir, ich würde die Lösung gemeinsam nutzen. Ich habe die folgende Anweisung in meiner httpd.conf- Datei verwendet:

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

Ändern Sie example.comIhren Domainnamen. Fügen Sie dies <VirtualHost x.x.x.x:xx>in Ihre httpd.conf- Datei ein. Beachten Sie, dass diese Anweisung nicht für HTTPS gilt , wenn Sie VirtualHostein Port-Suffix haben (z. B. :80). Sie müssen daher auch zu / etc / apache2 / sites-available / default-ssl gehen und dieselbe Anweisung in diese Datei einfügen des <VirtualHost _default_:443>Abschnitts.

Sobald die Konfigurationsdateien aktualisiert wurden, müssen Sie die folgenden Befehle im Terminal ausführen:

a2enmod headers
sudo service apache2 reload

Ich mag diese Option und habe sie mit der Implementierung von @George kombiniert / modifiziert. Manchmal ist auf Servern kein a2enmod verfügbar. Überprüfen Sie daher in Ihrer Haupt-httpd.conf, ob die Zeile LoadModule headers_module modules / mod_headers.so nicht kommentiert ist.
Mike Kormendy

Mein Ursprung hatte eine Portnummer, daher habe ich den regulären Ausdruck so geändert, dass er ^http(s)?://(.+\.)?example\.com(:\d+)?$
Folgendes

5

Wenn Sie Probleme mit Schriftarten haben, verwenden Sie:

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

3

Ein flexiblerer Ansatz ist die Verwendung der Ausdrücke von Apache 2.4. Sie können mit Domänen, Pfaden und nahezu jeder anderen Anforderungsvariablen übereinstimmen. Obwohl die gesendete Antwort immer ist *, sind die einzigen Anforderer, die sie erhalten, diejenigen, die die Anforderungen trotzdem erfüllen. Die Verwendung des Origin(oder eines anderen) Anforderungsheaders im Ausdruck führt dazu, dass Apache ihn automatisch in den VaryAntwortheader einfügt, sodass die Antwort nicht für einen anderen Ursprung wiederverwendet wird.

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

2
Ich bin hierher gekommen, weil einige Browser *Anmeldeinformationen wie Login nicht akzeptieren . Es ist also besser, wenn Sie den übereinstimmenden Hostnamen anstelle von übergeben *.
KeitelDOG

@KeitelDOG Wie erfasst man dynamisch den richtigen Ursprung und sendet ihn zurück, wenn mehrere Ursprünge vorhanden sind, anstatt den Code für jede Domain zu wiederholen? Es sieht aus wie es vielleicht mit Ausdrücken möglich sein , aber die docs klar ist nicht zu mir.
Walf

Tatsächlich war mein eigentliches Problem, dass Laravel den Access-Control-Allow-OriginHeader nicht für eine OPTIONSPreflight-Anforderung zurückgegeben hat, die nach Headern sucht, um festzustellen , ob der Server diesen Ursprung zulässt. Ich habe es repariert. War also *nicht das eigentliche Problem für mich. Einige Browser akzeptieren jedoch immer noch keine *Anmeldeinformationen. Wenn eine Webanwendung eine Cross-Origin-Anforderung sendet, MÜSSEN sie einen HTTP_ORIGINHeader angeben , auf den Sie möglicherweise dynamisch mit Variablen Originin .htaccessfür Apache oder $_SERVER['HTTP_ORIGIN'];in PHP zugreifen . Wie auch immer, Ihre Lösung ist gut, da sie alle Ursprünge zulässt, aber weniger sicher
KeitelDOG

Aber 2 Dinge, an die man sich erinnern sollte, sind: 1) Das Bereitstellen *erlaubt alles. 2) HOST unterscheidet sich von ORIGIN. HOST ist der tatsächliche 'ZIEL-HOST', der an den Anforderungsheader übergeben wird. Aber ORIGIN ist INITIAL HOSTderjenige, der die Anfrage an die sendet TARGET HOST. Daher wird in Ihrem Code ORIGIN HOSTignoriert und nie verwendet. Sehen Sie sich die Antworten oben an und Sie werden sehen, wie sie ORIGINWerte verwenden, um sie hinzuzufügen Access-Control-Allow-Origin.
KeitelDOG

@KeitelDOG Erlaubt *nicht jedem, da die Verwendung des OriginAnforderungsheaders im Ausdruck dazu führt, dass Apache ihn automatisch in den VaryAntwortheader zusammenführt, es sei denn, man verwendet req_novary('Origin')(wahrscheinlich unerwünscht). Browser wissen, dass sie möglicherweise eine andere Antwort für eine andere erhalten. OriginWenn der gesendete Wert den Test nicht besteht, wird der Access-Control-Allow-OriginHeader nie gesetzt.
Walf

3

PHP-Code:

$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 wird nicht von allen Browsern verwendet. Wie sicher ist HTTP_ORIGIN? Für mich ist es in FF leer.
Ich habe die Sites, denen ich den Zugriff auf meine Site erlaube, über eine Site-ID gesendet. Anschließend überprüfe ich meine Datenbank auf den Datensatz mit dieser ID und erhalte den Spaltenwert SITE_URL (www.yoursite.com).

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

Selbst wenn eine gültige Site-ID gesendet wird, muss die Anforderung von der Domäne stammen, die in meiner mit dieser Site-ID verknüpften Datenbank aufgeführt ist.


2

Hier ist eine erweiterte Option für Apache, die einige der neuesten und geplanten Schriftartdefinitionen enthält:

<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

Um den Zugriff auf mehrere Domänen für einen ASMX-Dienst zu erleichtern, habe ich diese Funktion in der Datei global.asax erstellt:

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();
    }
}

Dies ermöglicht auch die CORS-Behandlung von OPTIONSVerben.


2

PHP-Codebeispiel für übereinstimmende Subdomains.

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

2

Für ein relativ einfaches Kopieren / Einfügen für .NET-Anwendungen habe ich dies geschrieben, um CORS aus einer global.asaxDatei heraus zu aktivieren . Dieser Code folgt den Ratschlägen in der aktuell akzeptierten Antwort und spiegelt den Ursprung wider, der in der Anfrage in der Antwort angegeben ist. Dies erreicht effektiv '*', ohne es zu verwenden.

Der Grund dafür ist, dass mehrere andere CORS-Funktionen aktiviert werden, einschließlich der Möglichkeit, eine AJAX XMLHttpRequest mit dem Attribut 'withCredentials' auf 'true' zu senden.

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

Und noch eine Antwort in Django. Damit eine einzelne Ansicht CORS aus mehreren Domänen zulässt, ist hier mein 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

AWS Lambda / API-Gateway

Informationen zum Konfigurieren mehrerer Ursprünge auf Serverless AWS Lambda und API Gateway finden Sie hier: Eine ziemlich umfangreiche Lösung für etwas, das Ihrer Meinung nach recht einfach sein sollte:

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


Es ist derzeit nicht möglich, mehrere Ursprünge in API Gateway zu konfigurieren, siehe hier: https://docs.aws.amazon.com/apigateway/latest/developerguide/how-to-cors-console.html ), aber die Empfehlung (in Die Antwort oben lautet:

  • Überprüfen Sie den vom Browser gesendeten Origin-Header
  • Überprüfen Sie es anhand einer Whitelist der Herkunft
  • Wenn dies übereinstimmt, geben Sie den eingehenden Origin als Header für Access-Control-Allow-Origin zurück. Andernfalls geben Sie einen Platzhalter zurück (Standardursprung).

Die einfache Lösung besteht offensichtlich darin, ALL (*) wie folgt zu aktivieren:

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([{

Es ist jedoch möglicherweise besser, dies auf der API-Gateway-Seite zu tun (siehe 2. Link oben).


2
Access-Control-Allow-Credentials: trueist mit Platzhalter nicht erlaubt Access-Control-Allow-Origin: *. Stellen Sie <origin>stattdessen eine bestimmte ein.
Tom

@ Tom, ja, ich bin mir nicht sicher, warum das dort war, ich kann mich nicht erinnern, aber ich hätte es möglicherweise aus den Standardeinstellungen kopiert, die in AWS hinzugefügt wurden? Vielen Dank, dass Sie darauf hingewiesen haben.
timhc22

0

Die Antwort von Google auf die Schaltung von Anzeigen über SSL und die Grammatik im RFC selbst scheinen darauf hinzudeuten, dass Sie die URLs durch Leerzeichen begrenzen können. Ich bin mir nicht sicher, wie gut dies in verschiedenen Browsern unterstützt wird.


"Anzeigen über SSL schalten" verweist auf die Spezifikation w3.org/TR/cors/#access-control-allow-origin-response-header, die den Hinweis "In der Praxis ist die Produktion von Ursprungslisten oder Nullen eingeschränkter Anstatt eine durch Leerzeichen getrennte Liste von Ursprüngen zuzulassen, handelt es sich entweder um einen einzelnen Ursprung oder um die Zeichenfolge "null".
spazm

Es ist zwar wichtig, dieses Detail zu beachten, aber wenn in einer Spezifikation "In der Praxis" steht, bedeutet dies nicht, dass es nur gültig ist, dies auf diese Weise zu tun. Wenn Sie dies auf diese Weise tun, können Probleme auftreten, da die meisten Implementierer die Spezifikation entweder falsch oder unvollständig implementieren. Die Spezifikation erlaubt eine durch Leerzeichen getrennte Liste der Ursprünge, die Sie hier im EBNF unter origin-list: tools.ietf.org/html/rfc6454#section-7.1
Bob Aman

0

Wenn Sie so viele Codebeispiele wie mich ausprobieren, damit es mit CORS funktioniert, müssen Sie zuerst Ihren Cache leeren, um zu versuchen, ob es tatsächlich funktioniert, ähnlich wie bei Problemen, wenn alte Bilder noch vorhanden sind, auch wenn dies der Fall ist auf dem Server gelöscht (weil es noch in Ihrem Cache gespeichert ist).

Zum Beispiel CTRL + SHIFT + DELin Google Chrome, um Ihren Cache zu löschen.

Dies hat mir geholfen, diesen Code zu verwenden, nachdem ich viele reine .htaccessLösungen ausprobiert hatte , und dies schien die einzige zu sein, die funktionierte (zumindest für mich):

    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>

Beachten Sie auch, dass es weit verbreitet ist, dass viele Lösungen sagen, dass Sie tippen müssen, Header set ...aber es ist Header add .... Ich hoffe, das hilft jemandem, der seit einigen Stunden die gleichen Probleme hat wie ich.


0

Die folgende Antwort ist spezifisch für C #, das Konzept sollte jedoch auf alle verschiedenen Plattformen anwendbar sein.

Um Cross Origin-Anforderungen von einer Web-API aus zuzulassen, müssen Sie Optionsanfragen für Ihre Anwendung zulassen und auf Controller-Ebene die folgenden Anmerkungen hinzufügen.

[EnableCors (UrlString, Header, Method)] Jetzt können die Ursprünge nur noch als Zeichenfolge übergeben werden. Wenn Sie also mehr als eine URL in der Anforderung übergeben möchten, übergeben Sie diese als durch Kommas getrennten Wert.

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


0

Für den Header Access-Control-Allow-Origin kann nur ein einziger Ursprung angegeben werden. Sie können den Ursprung in Ihrer Antwort jedoch entsprechend der Anforderung festlegen. Vergessen Sie auch nicht, den Vary-Header festzulegen. In PHP würde ich Folgendes tun:

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

Wir können dies auch in der Datei Global.asax für die Asp.net-Anwendung festlegen.

protected void Application_BeginRequest(object sender, EventArgs e)
    {

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

    }
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.