Kontrola dostępu-Allow-Origin Domeny wielu źródeł?

1049

Czy istnieje sposób na zezwolenie na wiele domen w wielu domenach za pomocą Access-Control-Allow-Originnagłówka?

Jestem tego świadomy *, ale jest zbyt otwarty. Naprawdę chcę pozwolić tylko na kilka domen.

Na przykład coś takiego:

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

Próbowałem powyższego kodu, ale wydaje się, że nie działa on w przeglądarce Firefox.

Czy można podać wiele domen, czy utknąłem tylko z jedną?

Thomas J Bradley
źródło
3
W najnowszym Firefoksie nie działały ani domeny rozdzielone przecinkami, ani domeny oddzielone spacją. Dopasowywanie do listy domen i umieszczanie jednego hosta w nagłówkach nadal zapewnia większe bezpieczeństwo i działa poprawnie.
Daniel W.
1
Jeśli masz problem z HTTPS, znalazłem rozwiązanie .
Alex W
7
ważna uwaga : zezwolenie tylko na domeny typu cretain wAccess-Control-Allow-Originnagłówku nie oznacza, że ​​inne domeny nie mogą wyzwolić metody w tym punkcie końcowym (np. metoda interfejsu API REST). Oznacza to po prostu, że niedozwolone źródła nie mogą używać wyniku w javascript (przeglądarka to zapewnia). Aby ograniczyć dostęp do punktu końcowego dla określonych domen, użyj filtru żądań po stronie serwera, który np. Zwraca HTTP 401 dla niedozwolonych domen.
klues
1
Zawsze powinieneś dołączać Vary: Originnagłówek, jeśli chcesz używać wielu adresów URL, patrz: fetch.spec.whatwg.org/#cors-protocol-and-http-caches
Null

Odpowiedzi:

861

Wygląda na to, że zalecanym sposobem jest, aby Twój serwer odczytał nagłówek Origin od klienta, porównaj to z listą domen, na które chcesz zezwolić, a jeśli to pasuje, wyświetl wartość Originnagłówka z powrotem do klienta jako Access-Control-Allow-Originnagłówek w odpowiedzi.

Z .htaccesswas może zrobić to tak:

# ----------------------------------------------------------------------
# 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>
Yesthatguy
źródło
41
Jest to zgodne z sugestią
Simon B.
153
Moim problemem z tą odpowiedzią jest to, że tak naprawdę nie pomaga mi to, ponieważ używamy CDN, i oczywiście nie możemy kontrolować, w jaki sposób CDN ustawia programowo nagłówki.
BT
6
Rzeczywisty przykład (Nginx) w mojej odpowiedzi poniżej - stackoverflow.com/a/12414239/6084
mjallday
71
Jeśli problemem są pamięci podręczne lub CDN, użyj nagłówka Vary, aby poinformować pamięć podręczną / CDN o zachowaniu oddzielnych odpowiedzi dla różnych wartości nagłówka żądania Origin. W odpowiedzi umieścisz nagłówek taki jak „Vary: Origin”. Pamięć podręczna / CDN wie, że powinna wysłać jedną odpowiedź na żądanie z nagłówkiem „Origin: foo.example.com ”, a inną odpowiedź na żądanie z nagłówkiem „Origin: bar.example.com ”.
Sean
10
@saturdayplace, jeśli masz dostęp do nagłówka Origin, minęło CORS.
Paul Draper,
222

Inne rozwiązanie, którego używam w 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");
}
Nikołaj Iwanow
źródło
12
Dlaczego nie skorzystać z podejścia zaproponowanego w stackoverflow.com/a/1850482/11635 [i nie wysłać wieloznacznika, tylko żądane pochodzenie]? To jest po prostu bardziej liberalne, nie osiągając nic więcej?
Ruben Bartelink,
15
mając header('Access-Control-Allow-Origin: *')czasami mówi, nie można korzystać z dziką kartę, jeśli poświadczenia flaga jest prawda - dzieje się, kiedy header('Access-Control-Allow-Credentials: true')prawdopodobnie. Więc lepiej, aby Zezwalać na powstanie $http_originsamego, jeśli warunki są spełnione
Rakib,
6
zamień ostatnią linię header("Access-Control-Allow-Origin: " . $http_origin);na, aby zadziałało
François Romain
2
Ten kod wydaje się wadliwy, ponieważ jeśli nie zostanie rozpoznany żaden nagłówek HTTP_ORIGIN, nie zostanie w ogóle ustawiony Access-Control-Allow-Origin, pozostawiając skrypt szeroko otwarty.
Stephen R
9
@ StephenR faktycznie „szeroko zamknięty” byłby dokładniejszy, ponieważ ma to na celu otwarcie skryptu na inne domeny;)
Kaddath,
113

To działało dla mnie:

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

Po włożeniu na .htaccesspewno będzie działać.

Jay Dave
źródło
24
najlepsze rozwiązanie dla mnie, ale dodałem obsługę portów (np. localhost: 3000 dla programistów): SetEnvIf Origin "^ http (s)?: // (. + \.)? (localhost | stackoverflow.com | example1.com) ( : [0-9] +)? $ "Origin_is = 0 $
vszurma
2
Spośród kilku odpowiedzi na temat przepełnienia stosu, ta zadziałała.
Meetai.com,
Musiałem dodać, żeby Header set Access-Control-Allow-Credentials trueto działało jak odpowiedź @George'a
99 problemów - Składnia nie jest 1
To działa na pewno, gdy używam Origin. Ale w niektórych przypadkach Origin nie jest dostępny w niektórych żądaniach i jest również specyficzny dla przeglądarki. Potem zdecydowałem się użyć Refererzamiast Origin. Używanie Refererdziała, ale problem polega na tym, że ustawia pełny adres URL z powrotem na Access-Control-Allow-OriginChcę wyciąć nazwę domeny Refereri przypisać ją Access-Control-Allow-Origin. Coś w tym stylu - echo http://example.com/index.php/ab/cd | cut -d'/' -f1,2,3w poleceniu bash. Czy można to zrobić w pliku konf (apache)? Dowolny pomysł?
3AK
1
To mi nie działa. Zawsze mam błąd kodu 500, gdy dodam 2 linie. Właściwie używając PHP 5.6.15
BoCyrill
91

Miałem ten sam problem z czcionkami woff, wiele subdomen musiało mieć dostęp. Aby zezwolić na poddomeny, dodałem coś takiego do mojego 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>

W przypadku wielu domen możesz po prostu zmienić wyrażenie regularne SetEnvIf.

Staugaard
źródło
4
Wykonał lewę. Upewnij się tylko, czy poprawnie dostosowałeś wyrażenie regularne. Musiałem dodać znak zapytania, aby zezwolić na samą domenę, np. (.*\.?example\.org)Dla example.comi sub.example.com.
trkoch
3
Czy są jakieś przemyślenia na temat dostosowania tego do IIS 7?
Mark
Czy to jednak nie pokonuje celu? Co uniemożliwi złośliwemu użytkownikowi fałszowanie wartości nagłówka Origin?
Grégory Joseph
1
@ GrégoryJoseph Access-Control-Allow-Origin nie polega na ukrywaniu zasobów przed kimś, kto może o to poprosić. Chodzi o to, aby uniemożliwić złośliwym witrynom wywoływanie ich przez użytkowników końcowych. W przypadku plików czcionek może to tylko skutecznie ograniczyć łączenie na gorąco czcionek, dlaczego (Mozilla / Firefox) nie zrobiły tego samego dla innych zasobów (js, css itp.) Jest poza mną.
Tracker1
@trkoch, w wyrażeniu regularnym jest błąd, który również pozwoli subexample.com . Powinieneś zmienić to na:((.*\.)?example\.org)
bluesmoon,
65

Oto jak ponownie wyświetlić nagłówek Origin, jeśli pasuje on do Twojej domeny z Nginx, jest to przydatne, jeśli chcesz wyświetlać czcionkę w wielu subdomenach:

location /fonts {
    # this will echo back the origin header
    if ($http_origin ~ "example.org$") {
        add_header "Access-Control-Allow-Origin" $http_origin;
    }
}
mjallday
źródło
Nie mogę zrozumieć, czym to się różni: add_header Access-Control-Allow-Origin *; Chcesz to wyjaśnić?
Anoyz
spowoduje to zwrócenie nagłówka, który upoważnia przeglądarkę do wysyłania tylko żądań z określonej domeny. jeśli zgaduję, powiem, że przeglądarka może autoryzować zawartość z innej domeny załadowanej na tej stronie, aby uzyskać dostęp do serwera w inny sposób.
mjallday
7
@Anoyz z jednej strony może istnieć zwiększone bezpieczeństwo, w którym „Zezwalaj *” jest niedozwolone, ale działa określona i zgodna nazwa hosta dla nagłówka zezwolenia. Przykład tutaj, jeśli chcesz wysłać informacje autoryzacyjne między domenami, nie możesz użyć „Zezwól *”
TCC
3
Czy .w example.org jest interpretowana jako dowolna wartość, ponieważ jest to wyrażenie regularne? W takim przypadku, czy omyłkowo pozwoliłoby to na niestandardową domenę TLD w przykładzie?
stuckj
1
Prawidłowe wyrażenie regularne powinno wynikać z "^example\.org$"tego, że musisz się upewnić, że haker nie prześlizgnie się po wyrażeniu regularnym za pomocą subdomainexample.org(użyj ^) lub example.orgevil(użyj $) lub examplezorg( \.
ucieknij
27

Oto, co zrobiłem dla aplikacji PHP, o którą prosi 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);
}

Jeśli żądający początek jest dozwolony przez mój serwer, zwróć go $http_originjako wartość Access-Control-Allow-Originnagłówka zamiast zwracać *symbol wieloznaczny.

Rakib
źródło
20

Jest jedna wada, o której powinieneś wiedzieć: jak tylko prześlesz pliki na zewnątrz CDN (lub innemu serwerowi, który nie zezwala na skrypty) lub jeśli twoje pliki są buforowane na serwerze proxy, zmiana odpowiedzi na podstawie „Origin” nagłówek żądania nie będzie działać.

znak
źródło
4
Czy możesz rozwinąć tę kwestię lub wskazać nam miejsce, w którym możemy znaleźć więcej informacji? Chcę to zrobić z Limelight i mam nadzieję, że się mylisz. Jeden z naszych techników powiedział, że dopóki nasz serwer CDN wysyła nagłówek, sam CDN będzie go wysyłać. Jeszcze go nie przetestowałem
BT
12
Jeśli problemem są pamięci podręczne lub CDN, użyj nagłówka Vary, aby poinformować pamięć podręczną / CDN o zachowaniu oddzielnych odpowiedzi dla różnych wartości nagłówka żądania Origin. W odpowiedzi umieścisz nagłówek taki jak „Vary: Origin”. Pamięć podręczna / CDN wie, że powinna wysłać jedną odpowiedź na żądanie z nagłówkiem „Origin: foo.example.com ”, a inną odpowiedź na żądanie z nagłówkiem „Origin: bar.example.com ”.
Sean
Vary: Origin nie jest obsługiwany przez Akamai , jedną z największych sieci CDN na rynku ... Więcej szczegółów również tutaj dostępnych
Brad Parks
20

W przypadku wielu domen w .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>
Jerzy
źródło
4
Ten fragment działa dla mnie idealnie. Ale nie rozumiem, co robi: D
Karl Adler
2
to zadziałało dla mnie, chociaż musiałem dodać „^”, tj.… SetEnvIf Origin ”^ http (s)?: // (www \.)?
gypsyDev
Robi to prawie tak samo jak stackoverflow.com/a/14034228/209139 . Tyle że składnia .htaccess jest o wiele trudniejsza do odczytania niż PHP. Header set Vary Originbyłoby miłym dodatkiem do tej odpowiedzi.
TRiG
1
Wielkie dzięki za pomoc
Cool Perfectionist
2
Musiałem się zmienić AccessControlAllowOrigin=$0$1na AccessControlAllowOrigin=$0. W przeciwnym razie nie działało to w przypadku źródeł HTTPS. http://example.comwyszedł poprawnie, ale https://example.comwyszedł jako https://example.coms, z dodatkowym sna końcu.
TRiG,
17

Użytkownicy Nginx zezwalają na CORS dla wielu domen. Podoba mi się przykład @ marshalla, chociaż jego odpowiedzi odpowiadają tylko jednej domenie. Aby dopasować listę domen i subdomen, to wyrażenie regularne ułatwia pracę z czcionkami:

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

Spowoduje to echo tylko nagłówków „Access-Control-Allow-Origin”, które pasują do podanej listy domen.

Adriano Rosa
źródło
Pomyśl, że musisz zablokować to wyrażenie regularne na końcu za pomocą \ z, ponieważ w przeciwnym razie dostęp do domeny domain3.com.badhacker.com byłby możliwy.
dft
@dft Definiujemy $ na końcu, co to robi
Adriano Rosa
Przepraszam, miałem na myśli w prawdziwym przykładzie, faktyczny post @AdrianoRosa robi to samo, co \ z
dft
16

W przypadku IIS 7.5+ z zainstalowanym modułem URL Rewrite 2.0 zobacz tę SO odpowiedź

Paco Zarate
źródło
13

Oto rozwiązanie dla aplikacji internetowej Java, oparte na odpowiedzi yesthatguy.

Korzystam z Jersey REST 1.x

Skonfiguruj plik web.xml, aby był świadomy Jersey REST i 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>

Oto kod dla 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;
}

}
duvo
źródło
Link powyżej wygasł, możesz dodać nowy lub zaktualizować odpowiedź o więcej szczegółów, Dzięki
RajKumar Samala
Dodałem więcej szczegółów, mam nadzieję, że to pomoże
duvo
12

Jak wspomniano powyżej, Access-Control-Allow-Originpowinno być unikalne i Varypowinno być ustawione naOrigin jeśli jesteś za CDN (Content Delivery Network).

Odpowiednia część mojej konfiguracji 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';
}
hernvnc
źródło
ma set $corsjakieś ukryte znaczenie, czy może jest specyficzne dla twojego conifg? wydaje się, że można go pominąć wraz z drugimif
Mikezter
Zgadza się, można to pominąć, jeśli jest to jedyny warunek, który testujesz, aby ustawić nagłówki, miałem wiele w mojej konfiguracji.
hernvnc
9

Może się mylę, ale o ile widzę Access-Control-Allow-Originma"origin-list" parametr as.

Z definicji an origin-listto:

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

I z tego, twierdzę, że różne źródła są akceptowane i powinny być oddzielone przestrzenią .

drAlberT
źródło
2
To wydaje się być poprawną interpretacją specyfikacji; to powiedziawszy, specyfikacja nie wydaje się być w pełni obsługiwana przez obecne przeglądarki (na przykład, właśnie przetestowałem to na Firefox 17.0 i potwierdziłem, że nie będzie działać).
Rick Riensche,
7
W sekcji specyfikacji CORS podano5.1 Access-Control-Allow-Origin Response Header , że lista początkowa jest ograniczona: Zamiast zezwalać na listę początkową oddzieloną spacjami, jest to albo pojedyncze źródło, albo ciąg „null”.
maxpolk
2
Jak wspomniałem w komentarzu do mojej własnej odpowiedzi, jest to część uwagi implementatora, a nie wymóg RFC 2119. „Prawidłową” odpowiedzią jest absolutnie użycie wartości rozdzielanych spacjami. Problem polega po prostu na tym, że implementacje są niekompletne, więc „poprawna” odpowiedź niekoniecznie działa. Powinno, ale tak nie jest. Jednak w przyszłości, wraz z poprawą implementacji, może się to zmienić.
Bob Aman
8

Do aplikacji ExpressJS możesz użyć:

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();
});
eyecatchUp
źródło
pozwoli to na wszystkie inne połączenia przez następne połączenie ...
Ievgen Naida
@IevgenNaida So? W czym problem?
eyecatchUp
7

Próbowałem to skonfigurować dla domeny z HTTPS, więc pomyślałem, że podzielę się tym rozwiązaniem. W pliku httpd.conf zastosowałem następującą dyrektywę :

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

Zmień example.comnazwę swojej domeny. Dodaj to do <VirtualHost x.x.x.x:xx>swojego pliku httpd.conf . Zauważ, że jeśli masz VirtualHostsufiks portu (np. :80), To ta dyrektywa nie będzie miała zastosowania do HTTPS, więc musisz także przejść do / etc / apache2 / sites-available / default-ssl i dodać tę samą dyrektywę do tego pliku, wewnątrz z<VirtualHost _default_:443> sekcji.

Po zaktualizowaniu plików konfiguracyjnych należy uruchomić następujące polecenia w terminalu:

a2enmod headers
sudo service apache2 reload
Alex W.
źródło
Podoba mi się ta opcja i połączyłem / zmodyfikowałem ją z implementacją, którą ma @George. Czasami serwery nie mają dostępnego a2enmod, więc wszystko, co musisz zrobić, to sprawdzić główny httpd.conf, aby sprawdzić, czy wiersz: LoadModule nagłówki_module moduły / mod_headers.so nie jest odkomentowany.
Mike Kormendy
Moje pochodzenie miało numer portu, więc zmodyfikowałem wyrażenie regularne, aby zawierało: ^http(s)?://(.+\.)?example\.com(:\d+)?$
indyw
5

Jeśli masz problemy z czcionkami, użyj:

<FilesMatch "\.(ttf|ttc|otf|eot|woff)$">
    <IfModule mod_headers>
        Header set Access-Control-Allow-Origin "*"
    </IfModule>
</FilesMatch>
rzeczownik
źródło
3

Bardziej elastycznym podejściem jest użycie wyrażeń Apache 2.4. Możesz dopasować do domen, ścieżek i niemal każdej innej zmiennej żądania. Chociaż odpowiedź jest zawsze wysyłana *, jedynymi osobami, które ją odbierają, i tak spełniają te wymagania. Użycie Originnagłówka żądania (lub dowolnego innego) w wyrażeniu powoduje, że Apache automatycznie łączy je z Varynagłówkiem odpowiedzi, dzięki czemu odpowiedź nie będzie ponownie używana dla innego źródła.

<IfModule mod_headers.c>
    <If "%{HTTP:Host} =~ /\\bcdndomain\\.example$/i && %{HTTP:Origin} =~ /\\bmaindomain\\.example$/i">
        Header set Access-Control-Allow-Origin "*"
    </If>
</IfModule>
Walf
źródło
2
Przybyłem tutaj, ponieważ niektóre przeglądarki nie akceptują *poświadczeń, takich jak Login. Tak więc lepiej będzie, jeśli podasz pasującą nazwę hosta zamiast *.
KeitelDOG,
@KeitelDOG, w jaki sposób można dynamicznie przechwycić poprawne pochodzenie i odesłać go z powrotem, gdy istnieje wiele źródeł, zamiast powtarzać kod dla każdej domeny? Wygląda na to, że to możliwe z wyrażeniami, ale dokumenty nie są dla mnie jasne.
Walf
W rzeczywistości moim prawdziwym problemem było to, że laravel nie zwrócił Access-Control-Allow-Originnagłówka OPTIONSżądania wstępnego sprawdzania, czy nagłówki sprawdzają, czy serwer zezwala na to pochodzenie. Mam to naprawione. To *nie był dla mnie prawdziwy problem. Ale nadal niektóre przeglądarki nie akceptują *z poświadczeniami, więc gdy aplikacja internetowa wysyła żądanie Cross-Origin, muszą określić HTTP_ORIGINnagłówek, który może uzyskać dostęp dynamicznie zmiennej Originw .htaccessApache lub $_SERVER['HTTP_ORIGIN'];PHP. W każdym razie twoje rozwiązanie jest dobre, ponieważ pozwala na wszystkie początki, ale mniej bezpieczne
KeitelDOG
Należy jednak pamiętać o 2 rzeczach: 1) Zapewnienie *pozwala na wszystko. 2) HOST różni się od POCHODZENIA. HOST to rzeczywisty „HOST TARGET” przekazywany do nagłówka żądania. Ale ORIGIN to ten, INITIAL HOSTktóry wysyła żądanie do TARGET HOST. Dlatego w kodzie ORIGIN HOSTjest ignorowany i nigdy nie jest używany. Zobacz odpowiedzi powyżej, a zobaczysz, jak wykorzystują ORIGINwartości, aby je dodać Access-Control-Allow-Origin.
KeitelDOG
@KeitelDOG *Nie zezwala wszystkim, ponieważ użycie Originnagłówka żądania w wyrażeniu powoduje, że Apache automatycznie scala go z Varynagłówkiem odpowiedzi, chyba że zostanie użyty req_novary('Origin')(prawdopodobnie niepożądane). Przeglądarki wiedzą, że mogą otrzymać inną odpowiedź na inną, Origina jeśli wysłana wartość nie przejdzie testu, Access-Control-Allow-Originnagłówek nigdy nie jest ustawiony.
Walf
2

HTTP_ORIGIN nie jest używany przez wszystkie przeglądarki. Jak bezpieczny jest HTTP_ORIGIN? Dla mnie jest pusta w FF.
Witryny, które zezwalam na dostęp do mojej witryny, przesyłam za pomocą identyfikatora witryny, a następnie sprawdzam, czy w mojej bazie danych nie ma rekordu o tym identyfikatorze, i otrzymuję wartość kolumny SITE_URL (www.yoursite.com).

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

Nawet jeśli przesłano prawidłowy identyfikator witryny, żądanie musi pochodzić z domeny wymienionej w mojej bazie danych powiązanej z tym identyfikatorem witryny.

mathius1
źródło
2

Oto rozszerzona opcja apache, która zawiera niektóre z najnowszych i planowanych definicji czcionek:

<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>
Mike Kormendy
źródło
2

Aby ułatwić dostęp do wielu domen dla usługi ASMX, utworzyłem tę funkcję w pliku 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();
    }
}

Pozwala to również na obsługę OPTIONSczasownika przez CORS .

Derek Wade
źródło
2

Przykład kodu PHP dla pasujących subdomen.

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

Dla dość łatwego kopiowania / wklejania dla aplikacji .NET napisałem to, aby włączyć CORS z global.asaxpliku. Ten kod jest zgodny z radą podaną w obecnie akceptowanej odpowiedzi, odzwierciedlając pochodzenie podane w zapytaniu w odpowiedzi. To skutecznie osiąga „*” bez użycia.

Powodem tego jest to, że umożliwia wiele innych funkcji CORS , w tym możliwość wysyłania AJAX XMLHttpRequest z atrybutem „withCredentials” ustawionym na „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" , "*");
    }
}
QA Collective
źródło
2

Kod 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');
Liakos
źródło
1

I jeszcze jedna odpowiedź w Django. Aby jeden widok zezwalał na CORS z wielu domen, oto mój kod:

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
Silvain
źródło
1

AWS Lambda / API Gateway

Aby uzyskać informacje na temat konfigurowania wielu źródeł w bezserwerowej AWS Lambda i API Gateway - aczkolwiek dość duże rozwiązanie dla czegoś, co mogłoby się wydawać, powinno być dość proste - zobacz tutaj:

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


Obecnie nie można skonfigurować wielu źródeł w API Gateway, patrz tutaj: https://docs.aws.amazon.com/apigateway/latest/developerguide/how-to-cors-console.html ), ale zalecenie (w odpowiedź powyżej) brzmi:

  • sprawdź nagłówek Origin wysłany przez przeglądarkę
  • sprawdź to na białej liście pochodzenia
  • jeśli pasuje, zwróć przychodzące źródło jako nagłówek Access-Control-Allow-Origin, w przeciwnym razie zwróć symbol zastępczy (domyślny początek).

Proste rozwiązanie oczywiście umożliwia WSZYSTKIE (*) w następujący sposób:

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

Ale może być lepiej zrobić to po stronie API Gateway (patrz 2. link powyżej).

timhc22
źródło
2
Access-Control-Allow-Credentials: truenie jest dozwolone przy użyciu symboli wieloznacznych Access-Control-Allow-Origin: *. <origin>Zamiast tego ustaw konkretny .
Tom
@Tom, tak, nie jestem pewien, dlaczego to tam było, nie pamiętam, ale mogłem skopiować z domyślnych ustawień dodanych w AWS? Dzięki za wskazanie tego.
timhc22
0

Odpowiedź Google na wsparcie w wyświetlaniu reklam za pośrednictwem protokołu SSL i gramatyka w samym RFC wydaje się wskazywać, że możesz spować adresy URL. Nie jestem pewien, jak dobrze jest to obsługiwane w różnych przeglądarkach.

Bob Aman
źródło
„wyświetlanie reklam przez ssl” prowadzi do specyfikacji w3.org/TR/cors/#access-control-allow-origin-response-header, która dodaje notatkę: „W praktyce tworzenie listy początkowej lub zerowej jest bardziej ograniczone Zamiast dopuszczać rozdzieloną spacjami listę początków, jest to albo pojedyncze źródło, albo ciąg „null”.
spazm
Chociaż należy zwrócić uwagę na ten szczegół, gdy specyfikacja mówi „W praktyce”, nie oznacza to, że można to zrobić tylko w ten sposób. Oznacza to, że jeśli zrobisz to w ten sposób, możesz napotkać problemy, ponieważ większość implementatorów albo implementuje specyfikację niepoprawnie lub niekompletnie. Specyfikacja dopuszcza rozdzieloną spacjami listę początków, którą można zobaczyć tutaj w EBNF pod origin-list: tools.ietf.org/html/rfc6454#section-7.1
Bob Aman
0

Jeśli spróbujesz użyć tak wielu przykładów kodu, jak ja, aby działało przy użyciu CORS, warto wspomnieć, że musisz najpierw wyczyścić pamięć podręczną, aby sprawdzić, czy rzeczywiście działa, podobnie jak w przypadku, gdy stare obrazy są nadal obecne, nawet jeśli są usunięty na serwerze (ponieważ nadal jest zapisany w pamięci podręcznej).

Na przykład CTRL + SHIFT + DELw Google Chrome, aby usunąć pamięć podręczną.

Pomogło mi to użyć tego kodu po wypróbowaniu wielu czystych .htaccessrozwiązań i wydawało mi się, że to jedyne działające (przynajmniej dla mnie):

    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>

Zauważ również, że jest szeroko rozpowszechnione, że wiele rozwiązań mówi, że musisz pisać, Header set ...ale tak jest Header add .... Mam nadzieję, że to pomaga komuś, kto ma takie same problemy od kilku godzin, jak ja.

AlexioVay
źródło
0

Poniższa odpowiedź jest specyficzna dla C #, ale koncepcja powinna mieć zastosowanie do wszystkich różnych platform.

Aby zezwolić na Żądanie krzyżowego pochodzenia z interfejsu internetowego, musisz zezwolić na Żądania opcji do swojej aplikacji i dodać poniżej adnotację na poziomie kontrolera.

[EnableCors (UrlString, Header, Method)] Teraz początki mogą być przekazywane tylko jako ciąg. SO, jeśli chcesz przekazać więcej niż jeden adres URL w żądaniu, podaj go jako wartość oddzieloną przecinkami.

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

sakshi agrawal
źródło
0

W nagłówku Access-Control-Allow-Origin można określić tylko jedno źródło. Ale możesz ustawić pochodzenie w swojej odpowiedzi zgodnie z żądaniem. Nie zapomnij także ustawić nagłówka Vary. W PHP zrobiłbym następujące czynności:

    /**
     * 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
  }
Szymon
źródło
-2

Możemy to również ustawić w pliku Global.asax dla aplikacji Asp.net.

protected void Application_BeginRequest(object sender, EventArgs e)
    {

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

    }
sudhAnsu63
źródło