it-swarm.com.de

Zugriffskontrolle-Zulassen-Ursprung mehrerer Ursprungsdomänen?

Gibt es eine Möglichkeit, mehrere domänenübergreifende Domänen mit dem Access-Control-Allow-Origin-Header zuzulassen?

Ich kenne den *, aber er ist zu offen. Ich möchte 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 Domänen anzugeben oder bin ich mit nur einer Domäne verbunden?

896

Anscheinend ist die empfohlene Methode, den Origin-Header vom Client auszulesen, mit der Liste der Domänen zu vergleichen, die Sie zulassen möchten, und den Wert des Origin-Headers an den Client zurückzugeben als Access-Control-Allow-Origin-Header in der Antwort.

Mit .htaccess geht das so:

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

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");
}
188
Nikolay Ivanov

Das hat für mich 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 Sie .htaccess eingeben, funktioniert es auf jeden Fall.

101
Jay Dave

Ich hatte das gleiche Problem mit woff-Schriftarten, mehrere Subdomains mussten Zugriff haben. Um Subdomains zuzulassen, habe ich meiner httpd.conf so etwas 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>

Bei mehreren Domänen können Sie einfach den regulären Ausdruck in SetEnvIf ändern.

85
Staugaard

So können Sie den Origin-Header zurückschicken, wenn er mit Nginx in Ihre Domäne passt. Dies ist nützlich, wenn Sie mehrere Subdomains einer Schriftart 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;
    }
}
59
mjallday

Folgendes habe ich für eine PHP -Anwendung gemacht, 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 Origin von meinem Server zugelassen wird, geben Sie $http_Origin selbst als Wert des Access-Control-Allow-Origin-Headers zurück, anstatt einen *-Platzhalter zurückzugeben.

22

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

18
Mark

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

Für Nginx-Benutzer, die CORS für mehrere Domänen zulassen. Ich mag das Beispiel des @ Marshalls, obwohl seine Antworten nur einer Domäne entsprechen. Um eine Liste von Domänen und Subdomänen abzugleichen, erleichtert diese Regex das Arbeiten mit Zeichensätzen:

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

Dadurch werden nur die Header "Access-Control-Allow-Origin" wiedergegeben, die der angegebenen Domänenliste entsprechen.

14
Adriano Rosa

Für IIS 7.5+ mit installiertem URL Rewrite 2.0-Modul siehe this SO Antwort .

14
Paco Zarate

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

Ich verwende Jersey REST 1.x

Konfigurieren Sie die web.xml so, dass sie Jersey REST und den CORSResponseFilter kennt

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

}
11
duvo

Wie oben erwähnt, sollte Access-Control-Allow-Origin eindeutig sein und Vary sollte auf Origin gesetzt sein, wenn 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';
}
9
hernvnc

Vielleicht bin ich falsch, aber soweit ich sehen kann, hat Access-Control-Allow-Origin einen "Origin-list" als Parameter.

Nach Definition ein Origin-list lautet:

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 ich behaupte, dass unterschiedliche Ursprünge zugelassen sind und Leerzeichen getrennt werden sollten.

7
drAlberT

Ich hatte Schwierigkeiten, dies für eine Domäne einzurichten, auf der HTTPS ausgeführt wird, also dachte ich, ich würde die Lösung teilen. Ich habe die folgende Direktive 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.com in Ihren Domainnamen. Fügen Sie dies in <VirtualHost x.x.x.x:xx> in Ihre httpd.conf -Datei ein. Wenn Ihre VirtualHost ein Port-Suffix hat (z. B. :80), gilt diese Anweisung nicht für HTTPS. Daher müssen Sie auch nach/etc/Apache2/sites-available/default-ssl gehen und dieselbe hinzufügen Direktive in dieser Datei im Abschnitt <VirtualHost _default_:443>.

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

a2enmod headers
Sudo service Apache2 reload
5
Alex W

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

Ein flexiblerer Ansatz ist die Verwendung der Ausdrücke von Apache 2.4. Sie können mit Domains, Pfaden und fast jeder anderen Anforderungsvariablen übereinstimmen. Die Antwort ist zwar * für alle, aber die einzigen Anforderer, die diese Antwort erhalten, sind diejenigen, die die Anforderungen trotzdem erfüllen.

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

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

app.use(function(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();
});
1
eyecatchUp

Hier ist eine erweiterte Option für Apache, die einige der neuesten und geplanten Schriftdefinitionen 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>
1
Mike Kormendy

Für ein relativ einfaches Kopieren/Einfügen für .NET-Anwendungen habe ich dieses geschrieben, um CORS in einer global.asax-Datei zu aktivieren. Dieser Code folgt den Hinweisen in der aktuell akzeptierten Antwort und spiegelt wider, was Origin in der Anfrage in der Antwort zurückgibt. Dies erreicht effektiv "*", ohne es zu verwenden. Der Grund dafür ist, dass es mehrere andere CORS-Funktionen ermöglicht, einschließlich der Möglichkeit, 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
QA Collective

Und noch eine Antwort in Django. Um eine einzige Ansicht zu erhalten, die 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
Silvain

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);
}
1
blak3r

HTTP_Origin wird nicht von allen Browsern verwendet. Wie sicher ist HTTP_ORIGIN? Für mich kommt es leer in FF.
Ich habe die Websites, die ich für den Zugriff auf meine Site zulasse, über eine Site-ID senden. Dann ü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 das Senden über eine gültige Standort-ID erfolgt, muss die Anforderung von der Domäne stammen, die in meiner DB aufgeführt ist, die dieser Standort-ID zugeordnet ist.

1
mathius1

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 OPTIONS Verb.

1
Derek Wade

Die folgende Antwort bezieht sich speziell auf C #, das Konzept sollte jedoch auf alle verschiedenen Plattformen anwendbar sein.

Um Cross-Origin-Anforderungen von einer Web-API zuzulassen, müssen Sie Ihrer Anwendung Optionsanforderungen und der Anmerkung "Hinzufügen" auf Controller-Ebene hinzufügen.

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

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

0
sakshi agrawal

Die Support-Antwort von Google für das Bereitstellen von Anzeigen über SSL und die Grammatik im RFC selbst scheinen darauf hinzudeuten, dass Sie die URLs durch Leerzeichen trennen können. Sie sind sich nicht sicher, wie gut dies in verschiedenen Browsern unterstützt wird.

0
Bob Aman

Wenn Sie so viele Codebeispiele wie mich ausprobieren, damit es mit CORS funktioniert, ist es erwähnenswert, dass Sie zuerst Ihren Cache leeren müssen, um zu prüfen, ob es tatsächlich funktioniert auf dem Server gelöscht (weil es noch in Ihrem Cache gespeichert ist).

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

Dies hat mir geholfen, diesen Code zu verwenden, nachdem ich viele reine .htaccess-Lösungen ausprobiert hatte, und dies schien der einzige zu sein, der funktioniert (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 in vielen Lösungen Header set ... eingegeben werden muss, es sich jedoch um Header add ... handelt. Hoffe, das hilft jemandem, der seit einigen Stunden die gleichen Probleme hat wie ich.

0
AlexioVay

Für den Header Access-Control-Allow-Origin kann nur ein einziger Origin angegeben werden. Sie können jedoch den Ursprung in Ihrer Antwort entsprechend der Anforderung festlegen. Vergessen Sie auch nicht, den Vary-Header zu setzen. 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
  }
0
Simon