Как работает заголовок Access-Control-Allow-Origin?

По-видимому, я совершенно неправильно понял его семантику. Я подумал о чем-то вроде этого:

  • Клиент загружает код javascript MyCode.js из http://siteA - источник.
  • Заголовок ответа MyCode.js содержит Access-Control-Allow-Origin: http://siteB, который, как я думал, означал, что MyCode.js разрешено делать ссылки с перекрестными ссылками на сайт В.
  • Клиент запускает некоторые функции MyCode.js, которые, в свою очередь, запрашивают http://siteB, что должно быть хорошо, несмотря на то, что они являются запросами на кросс-начало.

Хорошо, я ошибаюсь. Это не работает так. Итак, я прочитал совместное использование ресурсов для разных источников и попытался прочитать совместное использование ресурсов Cross-Origin в рекомендации w3c.

Одно можно сказать наверняка - я до сих пор не понимаю, как я должен использовать этот заголовок.

У меня есть полный контроль над сайтом A и сайтом B. Как включить код javascript, загруженный с сайта A, для доступа к ресурсам на сайте B с помощью этого заголовка?

P.S.

Я не хочу использовать JSONP.

Ответ 1

Access-Control-Allow-Origin является заголовок CORS (перекрестный источник ресурсов).

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

Для каждого ресурса/страницы, которую сайт B хочет сделать доступным для сайта A, сайт B должен обслуживать свои страницы с заголовком ответа:

Access-Control-Allow-Origin: http://siteA.com

Современные браузеры не будут блокировать междоменные запросы прямо. Если сайт A запрашивает страницу с сайта B, браузер действительно будет запрашивать запрашиваемую страницу на сетевом уровне и проверяет, соответствуют ли заголовки ответов Site A как разрешенный домен реквестера. Если сайт B не указал, что сайту A разрешен доступ к этой странице, браузер вызывает событие XMLHttpRequest error и отказывает данные ответа запрашивающему JavaScript-коду.

Непростые запросы

Что происходит на сетевом уровне, может быть немного сложнее, чем описано выше. Если запрос является "непростым" запросом, браузер сначала отправляет запрос OPEL без предпросмотра, чтобы убедиться, что сервер будет принимать запрос. Запрос не прост, если либо (или оба):

  • с использованием 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 для непростых глаголов), которые соответствуют непростым глаголам и/или непростым заголовкам, тогда браузер отправляет фактический запрос.

Предположим, что сайт A хочет отправить запрос 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 для получения дополнительной информации о непростых запросах.

Ответ 2

Совместное использование запросов на основе перекрестных ссылок - CORS (запрос AJAX с междоменным доменом AKA) - это проблема, с которой может столкнуться большинство веб-разработчиков, в соответствии с Same-Origin-Policy, браузеры ограничивают клиентский JavaScript в изолированной программной среде безопасности, обычно JS не может напрямую взаимодействовать с удаленным сервером из другого домена. В прошлом разработчики создали много сложных способов для достижения запроса ресурсов между доменами, наиболее часто используемыми способами являются:

  • Использовать Flash/Silverlight или серверную часть как "прокси" для связи с дистанционным управлением.
  • JSON With Padding (JSONP).
  • Встраивает удаленный сервер в iframe и связывается через фрагмент или window.name, ссылается здесь.

Эти сложные способы имеют более или менее некоторые проблемы, например, JSONP может привести к дыре в безопасности, если разработчики просто "оценивают" его и # 3 выше, хотя это работает, оба домена должны строить строгий контракт между собой, это ни гибкий или элегантный ИМХО:)

W3C внедрил совместное использование ресурсов Cross-Origin (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

Синие части, отмеченные мной выше, являются фактами ядра, заголовок запроса "Origin" указывает, откуда отправляется запрос на перекрестный запрос или запрос перед полетом ", заголовок ответа" 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

Ответ 3

Вопрос слишком стар, чтобы ответить, но я отправляю это для любой будущей ссылки на этот вопрос.

В соответствии с этой статьей в Mozilla Developer Network,

Ресурс создает HTTP-запрос с перекрестным происхождением, когда он запрашивает ресурс из другого домена или порта, чем тот, который обслуживает первый ресурс.

введите описание изображения здесь

Страница HTML, обслуживаемая с помощью http://domain-a.com, выполняет запрос <img> src для http://domain-b.com/image.jpg.
Многие страницы в Интернете сегодня загружают ресурсы, такие как стили CSS, изображения и сценарии из отдельных доменов (таким образом, это должно быть круто).

Политика одинакового происхождения

По соображениям безопасности браузеры ограничивают HTTP-запросы HTTP , инициированные из сценариев.
Например, XMLHttpRequest и Fetch следуют политике того же самого происхождения.
Таким образом, веб-приложение, использующее XMLHttpRequest или Fetch, может сделать HTTP-запросы своим собственным доменом.

Совместное использование ресурсов (CORS)

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

Механизм Механизм совместного использования ресурсов (CORS) предоставляет веб-серверам средства управления междоменным доступом, которые обеспечивают безопасную передачу данных между доменами.
Современные браузеры используют CORS в контейнере API - например, XMLHttpRequest или Fetch - для снижения рисков HTTP-запросов с кросс-началом.

Как работает CORS (заголовок Access-Control-Allow-Origin)

Wikipedia:

В стандарте 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: *

Ответ 4

Всякий раз, когда я начинаю думать о 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 с сайта malware.com, взаимодействовать с ним, должен решать mybank.com, а не malware.com. Если бы malicous.com мог установить собственные заголовки CORS, разрешающие собственный доступ JavaScript к mybank.com, это полностью аннулировало бы ту же политику происхождения.

Я думаю, что причиной моей плохой интуиции является точка зрения, которую я имею при разработке сайта. Это мой сайт со всем моим JavaScript, поэтому он не делает ничего вредоносного, и я должен указать, с какими другими сайтами может взаимодействовать мой JavaScript. Когда на самом деле я должен думать, какие другие сайты JavaScript пытается взаимодействовать с моим сайтом, и должен ли я использовать CORS, чтобы разрешить их?

Ответ 5

Используя 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);
  }

Ответ 6

Если вы хотите просто протестировать кросс-доменное приложение, в котором браузер блокирует ваш запрос, вы можете просто открыть свой браузер в небезопасном режиме и протестировать приложение без изменения кода и не сделать ваш код небезопасным. Из MAC OS вы можете сделать это из терминальной линии:

open -a Google\ Chrome --args --disable-web-security --user-data-dir

Ответ 7

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. Только тогда браузер позволит вашему сценарию получить результат этих запросов.

Ответ 8

Если вы используете PHP, попробуйте добавить следующий код в начале файла php:

Если вы используете localhost, попробуйте это:

header("Access-Control-Allow-Origin: *");

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

header("Access-Control-Allow-Origin: http://www.website.com");

Ответ 9

Я работаю с express 4 и node 7.4 и angular, у меня была такая же проблема, как мне помочь:
a) сторона сервера: в файле 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');

но мне это не нужно,
b) клиентская сторона: в send ajax вам нужно добавить: "withCredentials: true", например:

$http({
     method: 'POST',
     url: 'url, 
     withCredentials: true,
     data : {}
   }).then(function(response){
        // code  
   }, function (response) {
         // code 
   });

удачи.

Ответ 10

В 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 в создаваемом ионном приложении, которое должно получить доступ к отдельному флеш-серверу.

Ответ 11

Для совместного использования поперечного сечения установите заголовок: 'Access-Control-Allow-Origin':'*';

Php: header('Access-Control-Allow-Origin':'*');

Node: app.use('Access-Control-Allow-Origin':'*');

Это позволит обмениваться контентом для разных доменов.

Ответ 12

Просто вставьте следующий код в ваш файл 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>  

Ответ 13

Заголовок ответа Access-Control-Allow-Origin указывает, может ли ответ использоваться совместно с запрашивающим кодом из данного источника.

Header type Response       header
Forbidden header name      no

Ответ, который говорит браузеру разрешить коду из любого источника обращаться к ресурсу, будет включать следующее:

Access-Control-Allow-Origin: *

Для получения дополнительной информации посетите здесь....

Ответ 14

У меня возникла эта проблема и разрешаю использовать тег iframe, в атрибуте src вы помещаете внешний URL-адрес, нет необходимости вносить какие-либо изменения в целевую службу

<iframe src="http://yourService.html"></iframe>