Как работает заголовок Access-Control-Allow-Origin?
Видимо, я совершенно не понял ее семантику. Я думал о чем-то вроде этого:
- Клиент загружает код JavaScript MyCode.js с http://siteA - источник.
- Заголовок ответа MyCode.js содержит Access-Control-Allow-Origin: http: // siteB, что, как я думал, означало, что MyCode.js было разрешено делать ссылки на сайт B.
- Клиент запускает некоторые функциональные возможности MyCode.js, которые, в свою очередь, отправляют запросы на http://siteB, что должно быть хорошо, несмотря на то, что это запросы между источниками.
Ну, я не прав. Это не работает, как это вообще. Итак, я прочитал разделение ресурсов между источниками и попытался прочитать разделение ресурсов между источниками в рекомендации w3c
Одно можно сказать наверняка - я до сих пор не понимаю, как я должен использовать этот заголовок.
У меня есть полный контроль над сайтом A и сайтом B. Как включить код JavaScript, загруженный с сайта A, для доступа к ресурсам на сайте B с помощью этого заголовка?
PS
Я не хочу использовать JSONP.
21 ответ
Access-Control-Allow-Origin
является заголовком CORS (Cross-Origin Resource Sharing)
Когда сайт A пытается извлечь контент с сайта B, сайт B может отправить Access-Control-Allow-Origin
заголовок ответа, чтобы сообщить браузеру, что содержание этой страницы доступно для определенных источников. (Источник - это домен, а также схема и номер порта.) По умолчанию страницы сайта B недоступны для любого другого источника; с использованием Access-Control-Allow-Origin
заголовок открывает дверь для перекрестного доступа по конкретным запрашивающим источникам.
Для каждого ресурса / страницы, которые Сайт B хочет сделать доступными для Сайта A, Сайт B должен обслуживать свои страницы с заголовком ответа:
Access-Control-Allow-Origin: http://siteA.com
Современные браузеры не будут блокировать междоменные запросы напрямую. Если сайт A запрашивает страницу с сайта B, браузер фактически извлекает запрошенную страницуна сетевом уровне и проверяет, содержит ли заголовки ответа сайт A в качестве разрешенного домена запрашивающей стороны. Если сайт B не указал, что сайту A разрешен доступ к этой странице, браузер вызовет XMLHttpRequest
"serror
событие и запретить данные ответа запрашивающему коду JavaScript.
Не простые запросы
То, что происходит на уровне сети, может бытьнемного сложнее, чем объяснено выше. Если запрос является "непростым" запросом, браузер сначала отправляет запрос"предварительных полетов" OPTIONS без данных, чтобы убедиться, что сервер примет запрос. Запрос является непростым, когда либо (или оба):
- используя HTTP-глагол, отличный от GET или POST (например, PUT, DELETE)
- использование непростых заголовков запросов; заголовки простых запросов:
Accept
Accept-Language
Content-Language
Content-Type
(это просто, когда его значениеapplication/x-www-form-urlencoded
,multipart/form-data
, или жеtext/plain
)
Если сервер отвечает на предварительный просмотр OPTIONS с соответствующими заголовками ответа (Access-Control-Allow-Headers
для непростых заголовков, Access-Control-Allow-Methods
для непростых глаголов), которые соответствуют непростым глаголам и / или непростым заголовкам, тогда браузер отправляет фактический запрос.
Предположим, что сайт А хочет отправить запрос PUT для /somePage
с непростым Content-Type
ценность application/json
браузер сначала отправит предварительный запрос:
OPTIONS /somePage HTTP/1.1
Origin: http://siteA.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: Content-Type
Обратите внимание, что Access-Control-Request-Method
а также Access-Control-Request-Headers
добавляются браузером автоматически; Вам не нужно добавлять их. Этот предварительный просмотр OPTIONS получает заголовки успешного ответа:
Access-Control-Allow-Origin: http://siteA.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: Content-Type
При отправке фактического запроса (после выполнения предварительной проверки) поведение идентично тому, как обрабатывается простой запрос. Другими словами, непростой запрос, предпечатная проверка которого успешна, обрабатывается так же, как простой запрос (т. Е. Сервер все еще должен отправить Access-Control-Allow-Origin
снова за фактический ответ).
Браузеры отправляют актуальный запрос:
PUT /somePage HTTP/1.1
Origin: http://siteA.com
Content-Type: application/json
{ "myRequestContent": "JSON is so great" }
И сервер отправляет обратно Access-Control-Allow-Origin
так же, как и для простого запроса:
Access-Control-Allow-Origin: http://siteA.com
Посмотрите Понимание XMLHttpRequest через CORS для немного больше информации о непростых запросах.
Обмен запросами между источниками - CORS
(Междоменный AJAX-запрос AKA) - это проблема, с которой может столкнуться большинство веб-разработчиков. Согласно Same-Origin-Policy, браузеры ограничивают клиентский JavaScript в изолированной программной среде безопасности, обычно JS не может напрямую взаимодействовать с удаленным сервером из другого домена. В прошлом разработчики создавали множество хитрых способов достижения запроса к междоменным ресурсам, чаще всего с использованием следующих способов:
- Используйте Flash/Silverlight или серверную часть в качестве "прокси" для связи с удаленным.
- JSON с набивкой ( JSONP).
- Встраивает удаленный сервер в iframe и связывается через фрагмент или имя window.name, см. Здесь.
У этих хитрых способов есть более или менее некоторые проблемы, например, JSONP может привести к дыре в безопасности, если разработчики просто "оценят" ее, и № 3 выше, хотя это работает, оба домена должны заключать строгие контракты друг с другом, это ни гибко, ни элегантно ПО МОЕМУ МНЕНИЮ:)
W3C представила Cross-Origin Resource Sharing (CORS) в качестве стандартного решения, чтобы обеспечить безопасный, гибкий и рекомендуемый стандартный способ решения этой проблемы.
Механизм
На высоком уровне мы можем просто считать, что CORS - это контракт между клиентским вызовом AJAX из домена A и страницей, размещенной в домене B, типичный запрос / ответ Cross-Origin будет выглядеть так:
DomainA AJAX заголовки запроса
Host DomainB.com
User-Agent Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0) Gecko/20100101 Firefox/4.0
Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8,application/json
Accept-Language en-us;
Accept-Encoding gzip, deflate
Keep-Alive 115
Origin http://DomainA.com
Заголовки ответа DomainB
Cache-Control private
Content-Type application/json; charset=utf-8
Access-Control-Allow-Origin DomainA.com
Content-Length 87
Proxy-Connection Keep-Alive
Connection Keep-Alive
Синие части, которые я отмечал выше, были фактами ядра, "заголовок запроса" Происхождение "указывает, откуда исходит перекрестный запрос или запрос предварительной проверки", заголовок ответа "Access-Control-Allow-Origin" указывает, что эта страница допускает удаленный запрос от DomainA (если значение * указывает, разрешает удаленные запросы из любого домена).
Как я упоминал выше, W3 рекомендовал браузеру реализовать предварительныйзапрос перед отправкой фактически HTTP-запроса Cross-Origin, в двух словах это HTTP OPTIONS
запрос:
OPTIONS DomainB.com/foo.aspx HTTP/1.1
Если foo.aspx поддерживает HTTP-глагол OPTIONS, он может вернуть ответ, как показано ниже:
HTTP/1.1 200 OK
Date: Wed, 01 Mar 2011 15:38:19 GMT
Access-Control-Allow-Origin: http://DomainA.com
Access-Control-Allow-Methods: POST, GET, OPTIONS, HEAD
Access-Control-Allow-Headers: X-Requested-With
Access-Control-Max-Age: 1728000
Connection: Keep-Alive
Content-Type: application/json
Только если ответ содержит "Access-Control-Allow-Origin" И его значение равно "*" или содержит домен, который отправил запрос CORS, при выполнении этого обязательного условия браузер отправит фактический междоменный запрос и кеширует результат в "Preflight-Result-Cache".
Я писал о CORS три года назад: HTTP-запрос AJAX Cross-Origin
Вопрос слишком стар, чтобы ответить, но я публикую его для любой будущей ссылки на этот вопрос.
Согласно этой статье Mozilla Developer Network,
Ресурс отправляет HTTP-запрос перекрестного происхождения, когда запрашивает ресурс из другого домена или порта, отличного от того, который обслуживает первый ресурс.
HTML-страница подается с http://domain-a.com
делает <img>
запрос SRC для http://domain-b.com/image.jpg
,
Сегодня многие страницы в Интернете загружают ресурсы, такие как таблицы стилей CSS, изображения и скрипты, из разных доменов (поэтому это должно быть круто).
Политика одного происхождения
По соображениям безопасности браузеры ограничивают перекрестные HTTP- запросы, инициируемые из сценариев.
Например, XMLHttpRequest
а также Fetch
следовать политике того же происхождения.
Итак, веб-приложение, использующее XMLHttpRequest
или же Fetch
мог только сделать HTTP-запросы к своему собственному домену.
Обмен ресурсами между источниками (CORS)
Чтобы улучшить веб-приложения, разработчики попросили поставщиков браузеров разрешить междоменные запросы.
Механизм общего доступа к ресурсам между источниками (CORS) предоставляет веб-серверам средства управления междоменным доступом, которые обеспечивают безопасную междоменную передачу данных.
Современные браузеры используют CORS в контейнере API - например, XMLHttpRequest
или же Fetch
- чтобы снизить риски перекрестных HTTP-запросов.
Как работает CORS (Access-Control-Allow-Origin
заголовок)
Стандарт CORS описывает новые заголовки HTTP, которые обеспечивают браузерам и серверам способ запрашивать удаленные URL-адреса только при наличии разрешения.
Хотя некоторая проверка и авторизация может выполняться сервером, браузер, как правило, несет ответственность за поддержку этих заголовков и соблюдение ограничений, которые они налагают.
пример
Браузер отправляет
OPTIONS
запрос сOrigin HTTP
заголовок.Значением этого заголовка является домен, который обслуживал родительскую страницу. Когда страница из
http://www.example.com
пытается получить доступ к данным пользователя вservice.example.com
следующий заголовок запроса будет отправленservice.example.com
:Происхождение: http://www.example.com/
Сервер на
service.example.com
может ответить:Access-Control-Allow-Origin
(ACAO) заголовок в своем ответе, указывающий, какие сайты происхождения разрешены.
Например:Access-Control-Allow-Origin: http://www.example.com
Страница с ошибкой, если сервер не разрешает перекрестный запрос
Access-Control-Allow-Origin
(ACAO) заголовок с подстановочным знаком, который разрешает все домены:Access-Control-Allow-Origin: *
Всякий раз, когда я начинаю думать о CORS, моя интуиция о том, на каком сайте размещаются заголовки, неверна, как вы описали в своем вопросе. Для меня это помогает думать о цели той же политики происхождения.
Цель той же политики происхождения - защитить вас от вредоносного JavaScript на siteA.com, который получает доступ к частной информации, которую вы выбрали для обмена только с siteB.com. Без такой же политики происхождения JavaScript, написанный авторами siteA.com, может заставить ваш браузер отправлять запросы на siteB.com, используя ваши файлы cookie аутентификации для siteB.com. Таким образом, siteA.com может украсть секретную информацию, которой вы делитесь с siteB.com.
Иногда вам нужно работать с кросс-доменом, в который входит CORS. CORS ослабляет ту же политику происхождения для domainA.com, используя Access-Control-Allow-Origin
заголовок для перечисления других доменов (domainB.com), которым доверяют запуск JavaScript, который может взаимодействовать с domainA.com.
Чтобы понять, какой домен должен обслуживать заголовки CORS, подумайте об этом. Вы посещаете malware.com, который содержит JavaScript, который пытается сделать кросс-доменный запрос к mybank.com. Решение о том, устанавливает ли он заголовки CORS, ослабляют ли ту же политику происхождения, позволяющую JavaScript с вредоносного сайта взаимодействовать с ним, должен решать mybank.com, а не malware.com. Если бы malicous.com мог установить собственные заголовки CORS, разрешающие собственный доступ JavaScript к mybank.com, это полностью аннулировало бы ту же политику происхождения.
Я думаю, что причиной моей плохой интуиции является точка зрения, которую я имею при разработке сайта. Это мой сайт со всем моим JavaScript, поэтому он не делает ничего вредоносного, и я должен указать, с какими другими сайтами может взаимодействовать мой JavaScript. Когда на самом деле я должен думать, какие другие сайты JavaScript пытается взаимодействовать с моим сайтом, и должен ли я использовать CORS, чтобы разрешить их?
По моему собственному опыту, трудно найти простое объяснение, почему CORS вообще вызывает беспокойство.
Как только вы поймете, почему он там, заголовки и обсуждение станут намного понятнее. Я попробую в нескольких строках.
Все дело в файлах cookie. Файлы cookie хранятся на клиенте по его домену.
Пример истории: на вашем компьютере есть файл cookie для
yourbank.com
. Может быть, ваша сессия там.
Ключевой момент: когда клиент делает запрос к серверу, он отправляет файлы cookie, хранящиеся в домене, в котором находится клиент.
Вы вошли в свой браузер, чтобы
yourbank.com
. Вы просите показать все свои аккаунты.yourbank.com
получает стопку файлов cookie и отправляет ответ (ваши учетные записи).
Если другой клиент отправляет серверу запрос из другого источника, эти файлы cookie отправляются, как и раньше. Рух-рох.
Вы просматриваете
malicious.com
. Вредоносный делает кучу запросов в разные банки, в том числеyourbank.com
.
Поскольку файлы cookie проверяются должным образом, сервер авторизует ответ.
Эти куки собираются и отправляются - и теперь,
malicious.com
получил ответ отyourbank
.
Ой.
Итак, теперь становятся очевидными несколько вопросов и ответов:
- "Почему бы нам просто не заблокировать браузер от этого?" Ага. CORS.
- "Как нам это обойти?" Попросите сервер сообщить запросу, что CORS в порядке.
Используя React и Axios, присоедините прокси-ссылку к URL и добавьте заголовок, как показано ниже
https://cors-anywhere.herokuapp.com/
+ Your API URL
Просто добавив ссылку "Прокси", вы заработаете, но она также может снова выдать ошибку "Нет доступа". Следовательно, лучше добавить заголовок, как показано ниже.
axios.get(`https://cors-anywhere.herokuapp.com/[YOUR_API_URL]`,{headers: {'Access-Control-Allow-Origin': '*'}})
.then(response => console.log(response:data);
}
1. Клиент загружает код JavaScript MyCode.js из http://sitea/ - источник.
Код, который выполняет загрузку - ваш тег html-скрипта или xhr из javascript или чего-либо еще - поступил, скажем, с http://sitez/. И, когда браузер запрашивает MyCode.js, он отправляет заголовок Origin: "Origin: http://sitez/", потому что он может видеть, что вы запрашиваете siteA и siteZ!= SiteA. (Вы не можете остановиться или помешать этому.)
2. Заголовок ответа MyCode.js содержит Access-Control-Allow-Origin: http://siteb/, что, как я думал, означало, что MyCode.js было разрешено делать ссылки на сайт B.
нет. Это означает, что только siteB разрешено делать этот запрос. Таким образом, ваш запрос MyCode.js от siteZ получает ошибку, а браузер обычно ничего не дает. Но если вы заставите свой сервер вернуть ACAO: siteZ, вы получите MyCode.js . Или, если он отправит '*', это сработает, это впустит всех. Или если сервер всегда отправляет строку из заголовка Origin:... но... для безопасности, если вы боитесь хакеров ваш сервер должен разрешать только источники в шорт-листе, которым разрешено делать эти запросы.
Затем MyCode.js приходит с сайта A. Когда он отправляет запросы на сайт B, все они имеют перекрестное происхождение, браузер отправляет Origin: siteA, и siteB должен взять siteA, распознать его в коротком списке разрешенных запрашивающих и отправить обратно ACAO: siteA. Только тогда браузер позволит вашему сценарию получить результат этих запросов.
Я работаю с Express 4 и узлом 7.4 и угловой, у меня была та же проблема, мне помочь это:
а) сторона сервера: в файле app.js я даю заголовки для всех ответов, например:
app.use(function(req, res, next) {
res.header('Access-Control-Allow-Origin', req.headers.origin);
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
это должно быть раньше всех роутеров.
Я видел много добавленных заголовков:
res.header("Access-Control-Allow-Headers","*");
res.header('Access-Control-Allow-Credentials', true);
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
но мне это не нужно,
б) на стороне клиента: в send ajax вам нужно добавить: "withCredentials: true", например:
$http({
method: 'POST',
url: 'url,
withCredentials: true,
data : {}
}).then(function(response){
// code
}, function (response) {
// code
});
удачи.
Если вы используете PHP, попробуйте добавить следующий код в beaning файла php:
если вы используете localhost, попробуйте это:
header("Access-Control-Allow-Origin: *");
если вы используете внешние домены, такие как сервер, попробуйте это:
header("Access-Control-Allow-Origin: http://www.website.com");
Если вы хотите просто протестировать междоменное приложение, в котором браузер блокирует ваш запрос, вы можете просто открыть свой браузер в небезопасном режиме и протестировать свое приложение, не изменяя код и не делая ваш код небезопасным. Из MAC OS вы можете сделать это из терминальной линии:
open -a Google\ Chrome --args --disable-web-security --user-data-dir
В Python я использую Flask-CORS
библиотека с большим успехом. Это делает работу с CORS супер простой и безболезненной. Я добавил код из документации библиотеки ниже.
Установка:
$ pip install -U flask-cors
Простой пример, который позволяет CORS для всех доменов на всех маршрутах:
from flask import Flask
from flask_cors import CORS
app = Flask(__name__)
CORS(app)
@app.route("/")
def helloWorld():
return "Hello, cross-origin-world!"
Для более конкретных примеров см. Документацию. Я использовал простой пример, приведенный выше, чтобы обойти проблему CORS в создаваемом ионном приложении, которое должно получить доступ к отдельному флеш-серверу.
Просто вставьте следующий код в ваш файл web.config.
Отметил, что вы должны вставить следующий код в <system.webServer>
тег
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Headers" value="Content-Type" />
<add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" />
</customHeaders>
</httpProtocol>
Я не могу настроить его на внутреннем сервере, но с этими расширениями в браузерах у меня работают:
Для Firefox: Cors Everywhere
Для Google Chrome: разрешить CORS: Access-Control-Allow-Origin
Примечание. CORS у меня работает с такой конфигурацией:
Для обмена между источниками установите заголовок: 'Access-Control-Allow-Origin':'*';
Php: header('Access-Control-Allow-Origin':'*');
Узел: app.use('Access-Control-Allow-Origin':'*');
Это позволит обмениваться контентом для другого домена.
Nginx и Appache
В дополнение к ответу апсиллера я хотел бы добавить вики-график, который показывает, когда запрос простой или нет (и предполетный запрос OPTIONS отправляется или нет)
Для простого запроса (например, хотлинкинга изображений) вам не нужно изменять файлы конфигурации сервера, но вы можете добавить заголовки в приложение (размещенное на сервере, например, в php), как упомянул Мелвин Герреро в своем ответе, - но помните: если вы добавите полный cors на вашем сервере (config), и в то же время вы разрешаете простые cors в приложении (например, php), это не будет работать вообще.
А вот конфигурации для двух популярных серверов.
включите CORS на Nginx (
nginx.conf
файл)location ~ ^/index\.php(/|$) { ... add_header 'Access-Control-Allow-Origin' "$http_origin" always; # if you change "$http_origin" to "*" you shoud get same result - allow all domain to CORS (but better change it to your particular domain) add_header 'Access-Control-Allow-Credentials' 'true' always; if ($request_method = OPTIONS) { add_header 'Access-Control-Allow-Origin' "$http_origin"; # DO NOT remove THIS LINES (doubled with outside 'if' above) add_header 'Access-Control-Allow-Credentials' 'true'; add_header 'Access-Control-Max-Age' 1728000; # cache preflight value for 20 days add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; # arbitrary methods add_header 'Access-Control-Allow-Headers' 'My-First-Header,My-Second-Header,Authorization,Content-Type,Accept,Origin'; # arbitrary headers add_header 'Content-Length' 0; add_header 'Content-Type' 'text/plain charset=UTF-8'; return 204; } }
включите CORS в Appache (
.htaccess
файл)# ------------------------------------------------------------------------------ # | Cross-domain Ajax requests | # ------------------------------------------------------------------------------ # Enable cross-origin Ajax requests. # http://code.google.com/p/html5security/wiki/CrossOriginRequestSecurity # http://enable-cors.org/ # change * (allow any domain) below to your domain Header set Access-Control-Allow-Origin "*" Header always set Access-Control-Allow-Methods "POST, GET, OPTIONS, DELETE, PUT" Header always set Access-Control-Allow-Headers "My-First-Header,My-Second-Header,Authorization, content-type, csrf-token" Header always set Access-Control-Allow-Credentials "true"
Заголовок ответа Access-Control-Allow-Origin указывает, может ли ответ использоваться совместно с запрашивающим кодом из данного источника.
Header type Response header
Forbidden header name no
Ответ, который говорит браузеру разрешить коду из любого источника обращаться к ресурсу, будет включать следующее:
Access-Control-Allow-Origin: *
Для получения дополнительной информации посетите здесь....
Возможно, очень глупый вопрос, но все же ... Куда мне это добавить?
Access-Control-Allow-Origin: http://siteA.com
Я что-то добавляю в свою конфигурацию Amazon S3 CORS?
Или это то, что мне нужно как-то передать с моим запросом, т.е. реализовать в собственном коде?
В моем случае у меня есть несколько скриптов, которые помещены в корзину S3, но они не работают из-за разрешений:
скрипт по адресу 'https://*******-bucket.s3.amazonaws.com/debug_toolbar/js/toolbar.js?AWSAccessKeyId=AKIAVIMsfsdfsdVNIPN&Signature=jVtM4%2FfsehifheiuIEmmUdAfPXN от http: // Expires от http: // 25% localhost:8000'заблокирован политикой CORS: на запрошенном ресурсе отсутствует заголовок'Access-Control-Allow-Origin'.
И если мне нужно реализовать это в моем коде - как это сделать? Я работаю с Django, и оба скрипта мне не принадлежат. Я думаю, мне нужно настроить некоторые настройки в S3Boto3Storage, которые я использую для использования S3?
Для .NET Core 3.1 API с Angular
Startup.cs : добавить CORS
//SERVICES
public void ConfigureServices(IServiceCollection services){
//CORS (Cross Origin Resource Sharing)
//=====================================
services.AddCors();
}
//MIDDLEWARES
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseRouting();
//ORDER: CORS -> Authentication -> Authorization)
//CORS (Cross Origin Resource Sharing)
//=====================================
app.UseCors(x=>x.AllowAnyHeader().AllowAnyMethod().WithOrigins("http://localhost:4200"));
app.UseHttpsRedirection();
}
}
Контроллер : включить CORS для авторизованного контроллера
//Authorize all methods inside this controller
[Authorize]
[EnableCors()]
public class UsersController : ControllerBase
{
//ActionMethods
}
Я использовал только расширение google chrome:Allow CORS: Access-Control-Allow-Origin
Рекомендуем посмотреть учебник
Кто не может контролировать бэкэнд для Options 405 Method Not Allowed
.
Обходной путь для браузера Chrome.
выполнить в командной строке:"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" --disable-web-security --user-data-dir="path_to_profile"
Пример:"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" --disable-web-security --user-data-dir="C:\Users\vital\AppData\Local\Google\Chrome\User Data\Profile 2"
Большинство проблем с CORS возникают из-за того, что вы пытаетесь запросить через ajax на стороне клиента приложения react, angular, jquery, которые являются базовыми библиотеками внешнего интерфейса.
Вы должны запросить из внутреннего приложения.
Вы пытаетесь запросить из внешнего API, но API, который вы пытаетесь использовать, ожидает, что этот запрос будет сделан из внутреннего приложения, и никогда не будет принимать запросы на стороне клиента.