Access-Control-Allow-Origin Домены нескольких источников?


1049

Есть ли способ разрешить несколько кросс-доменов, используя Access-Control-Allow-Originзаголовок?

Я знаю о *, но это слишком открыто. Я действительно хочу разрешить только пару доменов.

Как пример, примерно так:

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

Я пробовал приведенный выше код, но он не работает в Firefox.

Можно ли указать несколько доменов или я застрял только на одном?



3
Используя самый последний Firefox, ни разделенные запятой, ни разделенные пробелом домены не работали. Сопоставление со списком доменов и помещение одного хоста в заголовки по-прежнему повышает безопасность и работает правильно.
Даниэль В.

1
Если вы боретесь с этим для HTTPS, я нашел решение .
Алекс Вт

7
Важное примечание : разрешение только сохранять домены вAccess-Control-Allow-Originзаголовке не означает, что другие домены не могут вызвать метод на этой конечной точке (например, метод REST API). Это просто означает, что запрещенные источники не могут использовать результат в javascript (браузер гарантирует это). Для ограничения доступа к конечной точке для определенных доменов используйте фильтр запросов на стороне сервера, который, например, возвращает HTTP 401 для запрещенных доменов.
Клюз

1
Вы должны всегда добавлять Vary: Originзаголовок, если хотите использовать несколько URL-адресов, см. Fetch.spec.whatwg.org/#cors-protocol-and-http-caches
Null

Ответы:


861

Похоже, рекомендуемый способ сделать это - заставить ваш сервер читать заголовок Origin с клиента, сравнить его со списком доменов, которые вы хотели бы разрешить, и, если он совпадает, отобразить значение Originзаголовка обратно клиенту как Access-Control-Allow-Originзаголовок в ответе.

С помощью этого .htaccessвы можете сделать это так:

# ----------------------------------------------------------------------
# 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
Это соответствует тому, что предлагает W3C - w3.org/TR/cors/#access-control-allow-origin-response-hea
Саймон Б.

153
Моя проблема с этим ответом в том, что он мне не очень помогает, потому что мы используем CDN, и, очевидно, мы не можем контролировать, как CDN устанавливает заголовки программно.
BT

6
Актуальный пример (Nginx) в моем ответе ниже - stackoverflow.com/a/12414239/6084
mjallday

71
Если проблема связана с кешами или CDN, используйте заголовок Vary, чтобы указать кешу / CDN хранить отдельные ответы для разных значений заголовка запроса источника. Вы бы включили в свой ответ заголовок типа «Vary: Origin». Затем кэш / CDN знает, что он должен отправить один ответ на запрос с заголовком «Origin: foo.example.com » и другой ответ на запрос с заголовком «Origin: bar.example.com ».
Шон

10
@saturdayplace, если у вас есть доступ к заголовку Origin, вы прошли CORS.
Пол Дрейпер

222

Другое решение, которое я использую в 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
Почему бы не использовать подход, предложенный в stackoverflow.com/a/1850482/11635 [и не отправлять подстановочный знак, только запрашиваемое происхождение]? Это просто более допустимо без достижения чего-то большего?
Рубен Бартелинк

15
имея header('Access-Control-Allow-Origin: *')иногда говорит , что не может использовать джокер , если учетные данные флаг верно - бывает , когда , header('Access-Control-Allow-Credentials: true')вероятно. Таким образом, лучше разрешить-Происхождение самого $http_originсебя, если условия будут выполнены
Ракиб

6
заменить последнюю строку, header("Access-Control-Allow-Origin: " . $http_origin);чтобы заставить его работать
Франсуа Ромен

2
Этот код выглядит некорректным, поскольку если заголовок HTTP_ORIGIN не распознается, Access-Control-Allow-Origin вообще не устанавливается, оставляя сценарий широко открытым.
Стивен Р

9
@StephenR на самом деле "широко закрытый" был бы более точным, так как цель этого - открыть скрипт для других доменов;)
Kaddath

113

Это сработало для меня:

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

Когда вставлено .htaccess, это будет работать наверняка.


24
лучшее решение для меня, но я добавил поддержку портов (например, localhost: 3000 для разработки): SetEnvIf Origin "^ http (s)?: // (. + \.)? (localhost | stackoverflow.com | example1.com) ( : [0-9] +)? $ "Origin_is = $ 0
vszurma

2
Из нескольких ответов вокруг stackoverflow, это был тот, который работал.
Meetai.com

Мне нужно было добавить, Header set Access-Control-Allow-Credentials trueчтобы это работало как ответ @George
99 Проблемы - Синтаксис не один,

Это работает наверняка, когда я использую Origin. Но в некоторых случаях Origin не доступен в некоторых запросах, а также зависит от браузера. Тогда я решил использовать Refererвместо Origin. Использование Refererработает, но проблема в том, что он устанавливает полный URL-адрес обратно, Access-Control-Allow-Originя хочу вырезать доменное имя Refererи назначить его Access-Control-Allow-Origin. Что-то вроде результата этого - echo http://example.com/index.php/ab/cd | cut -d'/' -f1,2,3в команде bash. Можно ли сделать то же самое в (apache) conf файле? Есть идеи?
3AK

1
Это не работает для меня. Всегда с ошибкой кода 500, когда я добавляю 2 строки. На самом деле с помощью PHP
5.6.15

91

У меня была такая же проблема с woff-шрифтами, доступ к нескольким поддоменам должен был быть. Чтобы разрешить субдомены, я добавил что-то вроде этого в мой 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>

Для нескольких доменов вы можете просто изменить регулярное выражение в SetEnvIf.


4
Сделал трюк. Просто убедитесь, что вы правильно адаптировали регулярное выражение. Мне нужно было добавить знак вопроса, чтобы разрешить сам домен, например (.*\.?example\.org)для example.comи sub.example.com.
trkoch

3
Любые мысли о том, как адаптировать это для IIS 7?
Марк

Разве это не побеждает цель? Что помешает злоумышленнику подделать значение заголовка Origin?
Грегори Джозеф

1
@ GrégoryJoseph Access-Control-Allow-Origin не предназначен для сокрытия ресурсов от тех, кто может их запросить. Речь идет о предотвращении того, чтобы конечные пользователи вызывали ваш сайт. В случае файлов шрифтов это может эффективно ограничить только горячее связывание шрифтов, поэтому они (mozilla / firefox) не сделали то же самое для других ресурсов (js, css и т. Д.), Вне моего понимания.
Tracker1

@trkoch, в вашем регулярном выражении есть ошибка, это также позволит subexample.com. Вы должны изменить его на:((.*\.)?example\.org)
bluesmoon

65

Вот как вернуть заголовок Origin, если он соответствует вашему домену с Nginx, это полезно, если вы хотите обслуживать шрифт несколькими поддоменами:

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

Не могу понять, чем это отличается от: add_header Access-Control-Allow-Origin *; Хотите объяснить?
Anoyz

это вернет заголовок, который разрешает браузеру отправлять запросы только с указанного домена. если бы я догадался, я бы сказал, что браузер может авторизовать контент из другого домена, загруженного на эту страницу, для доступа к серверу в противном случае.
Миялдай

7
@Anoyz, с одной стороны, может быть повышенная безопасность, когда «Allow *» не разрешен, но работает указанное и соответствующее имя хоста для заголовка allow. Пример здесь, если вы хотите отправить авторизационную информацию между доменами, вы не можете использовать «Разрешить *»
TCC

3
.Интерпретируется ли в example.org любое значение, поскольку это регулярное выражение? В каком случае это по ошибке разрешит использовать пользовательский домен верхнего уровня?
stuckj

1
Правильное регулярное выражение должно быть, "^example\.org$"потому что вы должны убедиться, что хакер не может проскользнуть через ваше регулярное выражение с помощью subdomainexample.org(использования ^) или example.orgevil(использования $) или examplezorg(побега \.)
zeg

27

Вот что я сделал для приложения PHP, которое запрашивает 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);
}

Если запрашивающий источник разрешен моим сервером, верните $http_originсебя в качестве значения Access-Control-Allow-Originзаголовка вместо возврата *подстановочного знака.


20

Есть один недостаток, о котором вы должны знать: как только вы отправляете исходные файлы на CDN (или любой другой сервер, на котором не разрешены сценарии) или если ваши файлы кэшируются на прокси-сервере, изменение ответа основывается на «Origin» заголовок запроса не будет работать.


4
Не могли бы вы уточнить это или указать нам, где мы можем найти дополнительную информацию? Я собираюсь сделать это с помощью Limelight и надеюсь, что вы ошибаетесь. Один из наших техников сказал, что пока наш начальный сервер CDN отправляет заголовок, CDN сам отправит его. Еще не опробовал
BT

12
Если проблема связана с кешами или CDN, используйте заголовок Vary, чтобы указать кешу / CDN хранить отдельные ответы для разных значений заголовка запроса источника. Вы бы включили в свой ответ заголовок типа «Vary: Origin». Затем кэш / CDN знает, что он должен отправить один ответ на запрос с заголовком «Origin: foo.example.com » и другой ответ на запрос с заголовком «Origin: bar.example.com ».
Шон

Vary: Origin не поддерживается Akamai , одним из крупнейших CDN в мире ... Более подробная информация доступна также здесь
Брэд Паркс

20

Для нескольких доменов, в вашем .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
Этот фрагмент отлично работает для меня. Но я не понимаю, что он делает: D
Карл Адлер

2
это сработало для меня, хотя мне пришлось добавить '^', т.е. ... SetEnvIf Origin "^ http (s)?: // (www \.)?
gypsyDev

Он работает почти так же, как stackoverflow.com/a/14034228/209139 . Просто синтаксис .htaccess читать намного сложнее, чем PHP. Header set Vary Originбыло бы хорошим дополнением к этому ответу.
TRiG

1
Большое спасибо за вашу помощь
Cool Perfectionist

2
Я должен был измениться AccessControlAllowOrigin=$0$1на AccessControlAllowOrigin=$0. В противном случае, это не сработало бы для источников HTTPS. http://example.comвышло правильно, но https://example.comвышло так же https://example.coms, с лишним sна конце.
TRiG

17

Для пользователей Nginx разрешить CORS для нескольких доменов. Мне нравится пример @ marshall, хотя его ответы соответствуют только одному домену. Чтобы сопоставить список доменов и поддоменов, это регулярное выражение облегчает работу со шрифтами:

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

Это будет отображать только заголовки «Access-Control-Allow-Origin», которые соответствуют данному списку доменов.


Думаю, вам нужно заблокировать это регулярное выражение в конце с помощью \ z, потому что в противном случае domain3.com.badhacker.com будет иметь доступ.
ТСП

@dft Мы определяем $ в конце, который делает это
Адриано Роза

Извините, я имел в виду этот пример, фактическое сообщение @AdrianoRosa делает то же самое, что и \ z
dft


13

Вот решение для веб-приложения Java, основанное на ответе yesthatguy.

Я использую Джерси REST 1.x

Сконфигурируйте web.xml, чтобы знать о REST Джерси и 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>

Вот код для 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

12

Как упоминалось выше, оно Access-Control-Allow-Originдолжно быть уникальным и Varyдолжно быть установлено, Originесли вы находитесь за CDN (Сеть доставки контента).

Соответствующая часть моей конфигурации 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';
}

имеет set $corsкакой-то скрытый смысл, или это просто специфично для вашего conifg? кажется, что его можно опустить вместе со вторымif
mikezter

Это верно, это может быть опущено, если это единственное условие, которое вы тестируете для установки заголовков, у меня было несколько в моей конфигурации.
hernvnc

9

Возможно, я ошибаюсь, но, насколько я вижу, Access-Control-Allow-Originимеет "origin-list"параметр as.

По определению это origin-list:

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

И из этого я утверждаю, что допускается различное происхождение и должно быть разделено пробелами .


2
Это, кажется, правильная интерпретация спецификации; Тем не менее, спецификации, похоже, не полностью поддерживаются текущими браузерами (например, я только что протестировал это на Firefox 17.0 и подтвердил, что он не будет работать).
Рик Ринше,

7
В разделе спецификации CORS5.1 Access-Control-Allow-Origin Response Header говорится, что origin-list ограничен: вместо того, чтобы разрешать разделить пробелами список источников, это либо один источник, либо строка «null».
maxpolk

2
Как я упоминал в комментарии к своему собственному ответу, это часть примечания для разработчиков, а не требования RFC 2119. «Правильный» ответ - использовать значения, разделенные пробелом. Проблема заключается в том, что реализации являются неполными, и поэтому «правильный» ответ не обязательно работает. Это должно, но это не так. Однако в будущем, когда реализации станут лучше, это может измениться.
Боб Аман

8

Для приложений ExpressJS вы можете использовать:

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

все остальные звонки будут разрешены следующим
звонком

@IevgenNaida Так? В чем проблема?
eyecatchUp

7

Я изо всех сил пытался настроить это для домена, работающего по протоколу HTTPS, поэтому я решил поделиться этим решением. Я использовал следующую директиву в моем файле 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>

Измените example.comсвое доменное имя. Добавьте это внутри <VirtualHost x.x.x.x:xx>в ваш файл httpd.conf . Обратите внимание, что если у вас VirtualHostесть суффикс порта (например :80), тогда эта директива не будет применяться к HTTPS, поэтому вам нужно будет также перейти в / etc / apache2 / sites-available / default-ssl и добавить эту же директиву в этот файл внутри из<VirtualHost _default_:443> раздела.

После того, как файлы конфигурации обновлены, вам нужно будет выполнить следующие команды в терминале:

a2enmod headers
sudo service apache2 reload

Мне нравится эта опция и она объединена / изменена с реализацией, которую имеет @George. Иногда на серверах нет доступного a2enmod, поэтому все, что вам нужно сделать, это проверить ваш основной httpd.conf, чтобы убедиться, что строка: LoadModule headers_module modules / mod_headers.so не закомментирована.
Майк Корменди

У моего источника был номер порта, поэтому я изменил регулярное выражение, ^http(s)?://(.+\.)?example\.com(:\d+)?$
добавив в него следующее

5

Если у вас проблемы со шрифтами, используйте:

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

3

Более гибкий подход заключается в использовании выражений Apache 2.4. Вы можете сопоставить домены, пути и практически все остальные переменные запроса. Хотя отправленный ответ всегда *, единственные, кто его получает, - те, которые в любом случае отвечают требованиям. Использование Origin(или любого другого) заголовка запроса в выражении заставляет Apache автоматически объединить его с Varyзаголовком ответа, чтобы ответ не использовался повторно для другого источника.

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

2
Я пришел сюда, потому что некоторые браузеры не принимают *учетные данные, такие как Логин. Так что будет лучше, если вы передадите соответствующее имя хоста вместо *.
KeitelDOG

@KeitelDOG, как можно динамически перехватить правильное происхождение и отправить его обратно, когда существует несколько источников, вместо того, чтобы повторять код для каждого домена? Похоже , что это может быть возможным с выражениями , но документы не ясны для меня.
Уолф

На самом деле моя настоящая проблема заключалась в том, что laravel не возвращал Access-Control-Allow-Originзаголовок для OPTIONSпредварительного запроса, который проверяет заголовки, чтобы увидеть, позволяет ли сервер это происхождение. Я исправил это. Так что *не было настоящей проблемой для меня. Но, тем не менее, некоторые браузеры не принимают *учетные данные, поэтому, когда веб-приложение отправляет запрос Cross-Origin, они ДОЛЖНЫ указывать HTTP_ORIGINзаголовок, к которому вы можете получить динамический доступ с помощью переменной Originв.htaccess для Apache, или $_SERVER['HTTP_ORIGIN'];в PHP. В любом случае, ваше решение хорошо, поскольку оно допускает все источники, но менее безопасно
KeitelDOG

Но следует помнить 2 вещи: 1) Предоставление *позволяет все. 2) ХОСТ отличается от ORIGIN. HOST - это фактический TARGET HOST, который передается в заголовок запроса. Но ORIGIN - это INITIAL HOSTтот, который отправляет запрос в TARGET HOST. Поэтому в вашем коде ORIGIN HOSTигнорируется и никогда не используется. Посмотрите ответы выше, и вы увидите, как они используют ORIGINзначения, чтобы добавить их в Access-Control-Allow-Origin.
KeitelDOG

@KeitelDOG *Не позволяет всем, потому что использование Originзаголовка запроса в выражении заставляет Apache автоматически объединить его с Varyзаголовком ответа, если не используетсяreq_novary('Origin') (вероятно, нежелательно). Браузеры знают, что они могут получить другой ответ для другого, Originи если отправленное значение не проходит тест, Access-Control-Allow-Originзаголовок никогда не устанавливается.
Уолф

3

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 используется не всеми браузерами. Насколько безопасен HTTP_ORIGIN? Для меня это выглядит пустым в FF.
У меня есть сайты, которым я разрешаю доступ к своему сайту, отправляю по идентификатору сайта, затем я проверяю свою базу данных на запись с этим идентификатором и получаю значение столбца SITE_URL (www.yoursite.com).

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

Даже если отправка через действительный идентификатор сайта, запрос должен быть от домена, указанного в моей БД, связанной с этим идентификатором сайта.


2

Вот расширенный вариант для Apache, который включает в себя некоторые из последних и запланированных определений шрифтов:

<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

Чтобы облегчить многодоменный доступ для службы ASMX, я создал эту функцию в файле 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();
    }
}

Это также позволяет CORS обрабатывать OPTIONSглагол.


2

Пример кода PHP для сопоставления поддоменов.

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

2

Для довольно простого копирования / вставки для приложений .NET я написал это, чтобы включить CORS изнутри global.asax файла. Этот код следует советам, данным в принятом в настоящее время ответе, отражая происхождение, указанное в запросе в ответе. Это эффективно достигает «*» без его использования.

Причина этого заключается в том, что он включает несколько других функций CORS , включая возможность отправки AJAX XMLHttpRequest с атрибутом withCredentials, установленным в значение 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

И еще один ответ в Джанго. Чтобы иметь одно представление, разрешающее CORS из нескольких доменов, вот мой код:

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

Для получения информации о том, как настроить множественные источники на AWS Lambda и API Gateway без сервера - хотя довольно большое решение для чего-то, что можно было бы считать довольно простым - смотрите здесь:

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


В настоящее время невозможно настроить несколько источников в шлюзе API, см. Здесь: https://docs.aws.amazon.com/apigateway/latest/developerguide/how-to-cors-console.html ), но рекомендации (в ответ выше) это:

  • проверить заголовок источника, отправленный браузером
  • проверьте это против белого списка происхождения
  • если он совпадает, вернуть входящий Origin в качестве заголовка Access-Control-Allow-Origin, иначе вернуть заполнитель (источник по умолчанию).

Простое решение, очевидно, включает ALL (*) следующим образом:

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

Но может быть лучше сделать это на стороне шлюза API (см. 2-ю ссылку выше).


2
Access-Control-Allow-Credentials: trueне допускается с подстановочными знаками Access-Control-Allow-Origin: *. Установите конкретный <origin>вместо этого.
Том

@ Том, да, не уверен, почему это было там, я не помню, но я мог скопировать его из настроек по умолчанию, которые были добавлены в AWS? Спасибо за указание на это, хотя.
timhc22

0

Ответ службы поддержки Google на показ объявлений через SSL и грамматику в самом RFC , похоже, указывает на то, что вы можете разделять пробелы URL-адресами. Не уверен, насколько хорошо это поддерживается в разных браузерах.


« показ объявлений через ssl» ссылается на спецификацию w3.org/TR/cors/#access-control-allow-origin-response-header, в которой добавлено примечание: «На практике производство origin-list-or-null более ограничено Вместо того, чтобы разрешать разделенный пробелами список источников, это либо один источник, либо строка "null".
spazm

Хотя важно отметить эту деталь, когда в спецификации написано «На практике», это не значит, что это можно сделать только так. Это означает, что если вы сделаете это таким образом, вы можете столкнуться с проблемами, потому что большинство разработчиков либо реализуют спецификацию неправильно или не полностью. Спецификация допускает разделенный пробелами список источников, который вы можете увидеть здесь в EBNF по адресуorigin-list : tools.ietf.org/html/rfc6454#section-7.1
Боб Аман

0

Если вы попробуете так много примеров кода, как я, чтобы заставить его работать с использованием CORS, стоит упомянуть, что вы должны сначала очистить кеш, чтобы попытаться проверить, работает ли он на самом деле, аналогично проблемам, когда старые изображения все еще присутствуют, даже если удаляется на сервере (потому что он все еще сохраняется в вашем кэше).

Например CTRL + SHIFT + DELв Google Chrome удалить свой кеш.

Это помогло мне использовать этот код после того, как я попробовал много чистых .htaccessрешений, и это показалось единственным работающим (по крайней мере, для меня):

    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>

Также обратите внимание, что широко распространено, что многие решения говорят, что вы должны печатать, Header set ...но это так Header add .... Надеюсь, что это помогает кому-то, кто испытывает те же проблемы в течение нескольких часов, как я.


0

Ниже ответ специфичен для C #, но концепция должна быть применима ко всем различным платформам.

Чтобы разрешить перекрестные исходные запросы от веб-API, необходимо разрешить запросы Option для своего приложения и добавить примечание ниже на уровне контроллера.

[EnableCors (UrlString, Header, Method)] Теперь происхождение можно передавать только в виде строки. Поэтому, если вы хотите передать более одного URL-адреса в запросе, передайте его как разделенное запятыми значение.

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


0

Для заголовка Access-Control-Allow-Origin можно указать только один источник. Но вы можете установить источник в вашем ответе в соответствии с запросом. Также не забудьте установить заголовок Vary. В PHP я бы сделал следующее:

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

Мы также можем установить это в файле Global.asax для приложения Asp.net.

protected void Application_BeginRequest(object sender, EventArgs e)
    {

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

    }
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.