Кілька доменів доступу-контроль-дозволити-походження?


1049

Чи є спосіб дозволити декілька крос-доменів за допомогою Access-Control-Allow-Originзаголовка?

Мені відомо *, але це занадто відкрито. Я дуже хочу дозволити лише пару доменів.

Як приклад, щось подібне:

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

Я спробував вищевказаний код, але він, здається, не працює у Firefox.

Чи можна вказати кілька доменів або я застряг лише з одним?



3
За допомогою найсвіжішого Firefox не працювали ні розділені комами, ні домени, відокремлені пропуском. Збігання списку доменів та розміщення одного хоста в заголовках все ж є кращою безпекою та працює належним чином.
Даніель В.

1
Якщо ви боретеся з цим для HTTPS, я знайшов рішення .
Alex W

7
важливе зауваження : якщо дозволити лише домен cretain у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, щоб зберігати окремі відповіді на різні значення заголовка запиту Origin. У відповідь ви включите заголовок типу "Варіант: Походження". Потім кеш / CDN знає, що він повинен надіслати одну відповідь на запит із заголовком "Походження: foo.example.com " та іншу відповідь на запит із заголовком "Походження: 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собі Allow-Origin , якщо умови будуть дотримані
Ракіб

6
замініть останній рядок header("Access-Control-Allow-Origin: " . $http_origin);на, щоб він працював
Франсуа Ромен

2
Цей код видається недосконалим, оскільки якщо не розпізнається заголовок HTTP_ORIGIN, взагалі не встановлено жодного доступу Access Control-Allow-Origin, залишаючи сценарій широко відкритим.
Stephen R

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, коли я додаю два рядки. Фактично використовуючи PHP 5.6.15
BoCyrill

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 *; Хочете пояснити?
Анойз

це поверне заголовок, який дозволяє браузеру надсилати запити лише з вказаного домену. якби я здогадався, я б сказав, що браузер може авторизувати вміст з іншого домену, завантаженого на цій сторінці, щоб отримати доступ до сервера в іншому випадку.
mjallday

7
@Anoyz, з одного боку, може бути підвищена безпека, коли "Дозволити *" заборонено, але вказане і відповідне ім'я хоста для заголовка дозволу працює. Приклад тут, якщо ви хочете надіслати інформацію про авторизацію між домену, ви не можете використовувати "Дозволити *"
TCC

3
Чи .інтерпретується в example.org як будь-яке значення, оскільки це регулярний вираз? У такому випадку це помилково дозволить користувацький приклад-org TLD?
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 (або будь-який інший сервер, який не дозволяє сценаріїв) або якщо ваші файли кешуються на проксі, змінюючи відповідь на основі «Походження» заголовок запиту не працюватиме.


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

12
Якщо кеші або CDN викликають занепокоєння, використовуйте заголовок Vary, щоб повідомити кеш / CDN, щоб зберігати окремі відповіді на різні значення заголовка запиту Origin. У відповідь ви включите заголовок типу "Варіант: Походження". Потім кеш / CDN знає, що він повинен надіслати одну відповідь на запит із заголовком "Походження: foo.example.com " та іншу відповідь на запит із заголовком "Походження: 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, оскільки в іншому випадку домену3.com.badhacker.com буде дозволений доступ.
dft

@dft Ми визначаємо $ в кінці, що робить це
Адріано Роза

Вибачте, що я мав на увазі в суті прикладу, що фактична публікація @AdrianoRosa робить те саме, що і \ z
dft


13

Ось рішення для веб-програми Java, засноване на відповіді від yesthatguy.

Я використовую Джерсі REST 1.x

Налаштуйте web.xml так, щоб він був в курсі Jersey 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 (Network Delivery Network).

Відповідна частина моєї конфігурації 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якесь приховане значення, або воно просто специфічне для вашої хвойної породи? здається, що його можна опустити разом із другимif
мікестер

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

9

Можливо, я помиляюся, але, наскільки я бачу, Access-Control-Allow-Originмає "origin-list"параметр.

За визначенням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 зазначено, що список початків
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 module / mod_headers.so.
Майк Корменді

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

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
Я прийшов сюди, тому що деякі веб-переглядачі не приймають *такі дані, як Login. Тож буде краще, якщо ви передасте відповідне ім'я хоста замість *.
KeitelDOG

@KeitelDOG як динамічно фіксує правильне походження та надсилає його назад, коли існує декілька джерел, замість повторення коду для кожного домену? Схоже , що це може бути можливим з виразами , але документи не ясні для мене.
Вальф

Насправді моя справжня проблема полягала в тому, що laravel не повернув Access-Control-Allow-Originзаголовок для OPTIONSпередпольотного запиту, який перевіряє наявність заголовків, щоб перевірити, чи дозволяє сервер це походження. Я це виправив. Тож *не було для мене справжньою проблемою. Але деякі браузери все ще не приймають *облікові дані, тому коли веб-додаток надсилає запит Cross-Origin, вони мають вказати HTTP_ORIGINзаголовок, до якого ви можете динамічно отримати доступ зі змінною Originв .htaccessApache або $_SERVER['HTTP_ORIGIN'];PHP. У будь-якому разі ваше рішення добре, оскільки воно дозволяє усі джерела, але менш безпечні
KeitelDOG

Але слід пам’ятати 2 речі: 1) Надання *дозволяє все. 2) HOST відрізняється від ORIGIN. 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заголовок ніколи не встановлюється.
Вальф

2

HTTP_ORIGIN використовується не у всіх браузерах. Наскільки безпечний HTTP_ORIGIN? Для мене він виходить порожнім у ФФ.
У мене сайти, на які я дозволяю отримати доступ до свого сайту, надсилаються через ідентифікатор сайту, потім я перевіряю мій БД на запис із цим ідентифікатором і отримую значення стовпця 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();
    }
}

Це дозволяє також поводитись з OPTIONSдієсловом CORS .


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

2

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

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

Інформацію про те, як налаштувати декілька джерел на сервері 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, в іншому випадку поверніть заповнювач місця (початкове походження).

Просте рішення, очевидно, дозволяє ВСІМ (*) так:

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, яка додає примітку, "На практиці виробництво списку початків або нульове обмеження більш обмежене Замість того, щоб дозволити розділений пробілом список джерел, він є або єдиним початком, або рядком "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.