XMLHttpRequest не может загрузить XXX нет заголовка " Access-Control-Allow-Origin

tl; dr; о той же политике происхождения

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

XMLHttpRequest не удается загрузить https://www.example.com/ Заголовок "Access-Control-Allow-Origin" отсутствует в запрошенном заголовке ресурс. Происхождение'http://localhost:4300 ' поэтому доступ запрещен.

что мешает мне получить доступ к странице?

6 ответов


о той же политике происхождения

это Та Же Политика Происхождения. Это функция безопасности, реализованная браузерами.

ваш конкретный случай показывает, как он реализован для XMLHttpRequest (и вы получите идентичные результаты, если будете использовать fetch), но он также применяется к другим вещам (например, изображениям, загруженным на <canvas> или документы, загруженные в <iframe>), только с немного разными реализациями.

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

  • Алиса-это человек с веб-обозреватель
  • Боб работает веб-сайт (https://www.[website].com/ в вашем примере)
  • Мэллори запускает веб-сайт (http://localhost:4300 в вашем примере)

Алиса вошла на сайт Боба и имеет там некоторые конфиденциальные данные. Возможно, это интрасеть компании (доступная только для браузеров в локальной сети) или ее интернет-банкинг (доступен только с файлом cookie, который вы получаете после ввода имени пользователя и пароля).

Алиса посещает веб-сайт Мэллори, который имеет некоторый JavaScript, который заставляет браузер Алисы делать HTTP-запрос на веб-сайт Боба (с ее IP-адреса с ее куки и т. д.). Это может быть так же просто, как использование XMLHttpRequest и значение элемента responseText.

та же самая исходная политика браузера запрещает JavaScript читать данные, возвращаемые веб-сайтом Боба (который Боб и Алиса не хочу, чтобы Мэллори получил доступ). (Обратите внимание, что вы можете, например, отобразить изображение с помощью <img> элемент через origins, потому что содержимое изображения не подвергается JavaScript (или Mallory) ... если вы не бросаете холст в микс, и в этом случае вы будет создать ошибку нарушения того же происхождения).


почему одна и та же политика происхождения применяется, когда вы не думаете, что она должна

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

  • Алиса, Боб и Мэллори один и тот же человек.
  • Боб предоставляет полностью публичную информацию

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


почему Та же политика происхождения применяется только к JavaScript на веб-странице

расширения браузера, вкладка "сеть" в инструментах разработчика браузера и приложениях, таких как Postman, установлены программные средства. Они не передают данные с одного сайта на JavaScript, принадлежащий другому сайту только потому, что вы посетили этот другой веб-сайт. Установка программного обеспечения обычно требует более сознательного выбора.

нет третьей стороны (Мэллори), которая считается риск.


почему вы можете отображать данные на странице, не читая его с помощью JS

существует ряд обстоятельств, при которых сайт Мэллори может заставить браузер получать данные от третьей стороны и отображать их (например, добавив <img> элемент для вывода изображения). Для JavaScript Мэллори невозможно прочитать данные в этом ресурсе, хотя только браузер Алисы и сервер Боба могут это сделать, поэтому он все еще безопасный.


CORS

на Access-Control-Allow-Origin заголовок, указанный в сообщении об ошибке, является частью CORS стандарт, который позволяет Бобу явно предоставить разрешение на сайт Мэллори для доступа к данным через браузер Алисы.

базовая реализация будет включать в себя:

Access-Control-Allow-Origin: *

... разрешить любому веб-сайту читать данные.

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

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

особенности того, как вы устанавливаете этот заголовок ответа, зависят от HTTP-сервера и/или серверного языка программирования Боба. Есть коллекция руководств для различных общих конфигураций что может помочь.

NB: некоторые запросы являются сложными и отправить предполетный параметры запрашивают, что сервер будет должны ответить, прежде чем браузер отправит GET/POST/PUT/любой запрос, который JS хочет сделать. Реализации CORS, которые только добавляют Access-Control-Allow-Origin для конкретных URL-адресов часто спотыкаются об это.


очевидно, предоставление разрешения через CORS-это то, что Боб будет делать только в том случае, если:

  • данные не были частными или
  • Мэллори был надежным

если вы также Боб в этом сценарий, то особенности того, как вы добавляете заголовки разрешений CORS будет зависеть от некоторой комбинации вашего выбора программного обеспечения HTTP-сервера и какой язык вы используете для программирования на стороне сервера (если таковые имеются).

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


сообщения об ошибках, которые упоминают "Ответ для предполетного"

некоторые запросы cross origin являются preflighted.

это происходит, когда (грубо говоря) вы пытаетесь сделать кросс-доменный запрос:

  • включает учетные данные, такие как cookies
  • не может быть сгенерирован с обычной HTML-формой (например, имеет пользовательские заголовки или тип контента, который вы не можете использовать в форме enctype).

обратите внимание ,что "пользовательские заголовки" включают Access-Control-Allow-Origin и другие заголовки ответов CORS. Они не принадлежат запросу, не делают ничего полезного (какой смысл в системе разрешений, где вы можете предоставить себе разрешение?), и должны появляться только на ответе.

в этих случаях остальная часть этого ответа по-прежнему применяется но вам также нужно убедиться, что сервер может прослушивать запрос предполетной подготовки (который будет OPTIONS (а не GET, POST или то, что вы пытались отправить) и отвечайте на это правильно Access-Control-Allow-Origin заголовок, но и Access-Control-Allow-Methods и Access-Control-Allow-Headers чтобы разрешить ваши конкретные методы HTTP или заголовки.


альтернативы CORS

JSONP

Боб также может предоставить данные, используя хак как JSONP именно так люди делали cross-origin Ajax до появления CORS.

он работает, представляя данные в виде программы JavaScript, которая вводит данные в Мэллори страница.

это требует, чтобы Мэллори доверять Боб не предоставлять вредоносный код.

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

переместить два ресурса в один источник

если HTML-документ, в котором работает JS, и запрашиваемый URL-адрес находятся в одном и том же источнике (общая схема, имя хоста и порт), то они Та же политика Origin предоставляет разрешение по умолчанию. CORS не требуется.

Прокси

Мэллори мог бы используйте серверный код для получения данных (которые она могла бы передать со своего сервера в браузер Алисы через HTTP, как обычно).

- это:

  • добавить заголовки CORS
  • преобразовать ответ в JSONP
  • существует в том же происхождении, что и HTML документ

этот серверный код может быть размещен третьей стороной (например, YQL).

Бобу не нужно было бы предоставлять какие-либо разрешения для этого.

это было бы хорошо, так как это только между Мэллори и Бобом. Боб не может думать, что Мэллори-это Элис, и предоставлять Мэллори данные, которые должны храниться в тайне между Элис и Бобом.

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

писать что-то другое, чем веб-приложение

как отмечено в разделе "почему одна и та же политика происхождения применяется только к JavaScript на веб-странице", вы можете избежать SOP, не записывая JavaScript на веб-странице.

это не означает, что вы не можете продолжать использовать JavaScript и HTML, но вы можете распространять его с помощью другого механизма, такого как Node-WebKit или PhoneGap.

браузер расширения

расширение браузера может вводить заголовки CORS в ответ до применения той же политики происхождения.

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

они также имеют тенденцию работать только с простыми запросами (сбой при обработке параметров предполетной подготовки требования заказчика.)

наличие надлежащей среды разработки с локальным развитием сервер обычно это лучший подход.


другие риски для безопасности

обратите внимание, что SOP / CORS не смягчают межсайтовый скриптинг, CSRF в или SQL-инъекций атаки, которые необходимо обрабатывать независимо.


резюме

  • вы ничего не можете сделать в код код на стороне клиента, который позволит CORS доступ к кому-то другое сервер.
  • если вы управляете сервером, запрос выполняется: добавьте к нему разрешения CORS.
  • если вы дружите с человеком, который контролирует его: получить их, чтобы добавить разрешения CORS к нему.
  • если это общедоступная служба: прочитайте их документацию API, чтобы узнать, что они говорят о доступе к ней с помощью клиентского JavaScript. Они могут сказать вам использовать конкретные URL-адреса или использовать JSONP (или они могут не поддерживать его вообще).
  • если ничего из вышеперечисленного не подходит: браузер, чтобы поговорить с код сервер, а затем сервер получает данные с другого сервера и передать его. (Существуют также сторонние размещенные службы, которые прикрепляют заголовки CORS к общедоступным ресурсам, которые можно использовать).

Это происходит из-за ошибки CORS. CORS означает совместное использование ресурсов Cross Origin. Проще говоря, эта ошибка возникает при попытке доступа к домену / ресурсу из другого домена.

подробнее об этом здесь: ошибка CORS с jquery

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

как получить общий доступ к ресурсам кросс-происхождения (CORS) post request working

эти ссылки могут помочь


целевой сервер должен разрешить запрос перекрестного происхождения. Чтобы разрешить его через express, просто обработайте запрос параметров http:

app.options('/url...', function(req, res, next){
   res.header('Access-Control-Allow-Origin', "*");
   res.header('Access-Control-Allow-Methods', 'POST');
   res.header("Access-Control-Allow-Headers", "accept, content-type");
   res.header("Access-Control-Max-Age", "1728000");
   return res.sendStatus(200);
});

поскольку это не упоминается в принятом ответе.

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

если владелец сервера явно не предотвращает его каким - либо образом-вы можете использовать простые запросы.
обратите внимание, что 'простые вопросы' нужно выполнить несколько условий, в том числе только разрешение POST, GET и HEAD а также разрешить только некоторые заданные заголовки (вы можете найти все условия здесь).

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

хорошим индикатором для этого сценария может быть ошибка CORS, включая термин preflight.

этой это связанный вопрос здесь, в stackoverflow.


вы должны включить CORS, чтобы заставить его работать.


в случае, если вы получаете эту ошибку при разработке расширения для google chrome, просто добавьте -

  "permissions": [
"http://www.google.com/"

]

в манифесте.файл json.
** замените Google на ваш сторонний URL.