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

112

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

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

XMLHttpRequest не может загрузить https://www.example.com/ На запрошенном ресурсе отсутствует заголовок Access-Control-Allow-Origin. Следовательно, к источнику ' http: // localhost: 4300 ' не разрешен доступ.

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

Питер Дэвид Картер
источник
Я работаю над сайтом, пять минут назад все было хорошо.
Питер Дэвид Картер
1
выдает заголовки CORS? возможно, если бы вы поделились каким-то кодом, его было бы легче увидеть
Jaromanda X
Правдоподобно. В какой отдел мне следует попросить выяснить? Я в основном занимаюсь костяком и марионетками ...
Питер Дэвид Картер,
Да. Я полагаю, что организации отделов в любом случае не всегда единообразны, так что это, возможно, туманный вопрос, но я хотел бы немного узнать о бэкэнде / маршрутизации / системном администрировании в моей компании, и это казалось хорошим предлогом для ознакомления я сам, так что если в будущем возникнут проблемы, я могу помочь.
Питер Дэвид Картер
Я бы спросил у кого-нибудь на стороне сервера внутри вашей операции. Они должны были изменить его на вас, если вы могли получить к нему доступ раньше.
Ларри Лейн,

Ответы:

208

tl; dr - в конце есть сводка, а в ответе заголовки, чтобы было проще найти нужные части. Тем не менее, рекомендуется прочитать все, так как это дает полезную основу для понимания того, почему, это упрощает понимание того, как применяется в различных обстоятельствах.

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

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

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

(Как ни странно, это также применимо к шрифтам CSS, но это потому, что найденные литейщики настаивали на DRM, а не на проблемах безопасности, которые обычно покрывает политика одинакового происхождения).

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

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

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

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

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


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

Для любого заданного URL-адреса возможно, что СОП не требуется. Вот несколько распространенных сценариев, когда это так:

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

… Но браузер не имеет возможности узнать, верно ли что-либо из вышеперечисленного, поэтому доверие не является автоматическим, и применяется СОП. Разрешение должно быть предоставлено явным образом, прежде чем браузер передаст данные другому веб-сайту.


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

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

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

*Расширения браузера нужно писать осторожно, чтобы избежать проблем с перекрестным происхождением. См., Например, документацию Chrome .


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

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


CORS

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

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

Access-Control-Allow-Origin: *

… В заголовках ответов, чтобы любой веб-сайт мог читать данные.

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

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

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

Модель применения правил CORS

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


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

  • Данные не были личными или
  • Мэллори доверяли

Но я не Боб!

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

Если Боб запускает общедоступный API, то может быть механизм для включения CORS (возможно, путем форматирования запроса определенным образом или параметра конфигурации после входа на сайт портала разработчика для сайта Боба). Однако это должен быть механизм, реализованный Бобом. Мэллори может прочитать документацию на сайте Боба, чтобы узнать, доступно ли что-нибудь, или она может поговорить с Бобом и попросить его внедрить CORS.


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

Некоторые запросы на перекрестное происхождение проходят предварительную проверку .

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

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

Если вы правильно делаете что-то, что требует предполетной подготовки

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

Если вы по ошибке запускаете предполетную проверку

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

Распространенные ошибки, которые вызывают это, включают:

  • пытаюсь поставить Access-Control-Allow-Originи другие заголовки ответа CORS на запрос. Они не относятся к запросу, не делают ничего полезного (какой смысл в системе разрешений, в которой вы могли бы предоставить себе разрешение?), И должны появляться только в ответе.
  • попытка поместить Content-Type: application/jsonзаголовок в запрос GET, не имеющий тела запроса для описания содержимого (обычно, когда автор путает Content-Typeи Accept).

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


Непрозрачные ответы

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

Если вы используете в fetchAPI (вместо XMLHttpRequest), то вы можете настроить его , чтобы не пытаться использовать CORS.

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

Это позволит вам сделать простой запрос, не видеть ответа и не заполнять консоль разработчика сообщениями об ошибках.

Как это сделать, объясняется сообщением об ошибке Chrome, которое выдается, когда вы делаете запрос с помощью fetchи не получаете разрешения на просмотр ответа с помощью CORS:

Доступ к выборке https://example.com/из источника https://example.netзаблокирован политикой CORS: Access-Control-Allow-Originв запрошенном ресурсе отсутствует заголовок. Если непрозрачный ответ соответствует вашим потребностям, установите режим запроса на 'no-cors', чтобы получить ресурс с отключенным CORS.

Таким образом:

fetch("http://example.com", { mode: "no-cors" });

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

JSONP

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

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

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

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

Поскольку JSONP работает путем добавления <script>элемента для загрузки данных в форме программы JavaScript, которая вызывает функцию, уже находящуюся на странице, попытка использовать технику JSONP для URL-адреса, который возвращает JSON, не удастся - обычно с ошибкой CORB - потому что JSON не является JavaScript.

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

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

Прокси

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

Это либо:

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

Этот серверный код может быть написан и размещен третьей стороной (например, CORS Anywhere). Обратите внимание на последствия этого для конфиденциальности: третья сторона может отслеживать, кто какие прокси на своих серверах.

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

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

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

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

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

Как отмечалось в разделе «Почему одна и та же политика происхождения применяется только к JavaScript на веб-странице», вы можете избежать использования СОП, не написав JavaScript на веб-странице.

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

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

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

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

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

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


Прочие риски безопасности

Обратите внимание, что SOP / CORS не смягчают атаки XSS , CSRF или SQL Injection, которые необходимо обрабатывать независимо.


Резюме

  • Там нет ничего , что вы можете сделать в вашей стороне клиента код , который позволит CORS доступ к кто - либо серверу.
  • Если вы управляете сервером, выполняется запрос к: Добавьте к нему разрешения CORS.
  • Если вы дружите с человеком, который его контролирует: попросите его добавить к нему разрешения CORS.
  • Если это государственная услуга:
    • Прочтите их документацию по API, чтобы узнать, что они говорят о доступе к нему с помощью клиентского JavaScript:
      • Они могут посоветовать вам использовать определенные URL-адреса
      • Они могут поддерживать JSONP
      • Они могут вообще не поддерживать доступ между источниками из клиентского кода (это может быть осознанное решение по соображениям безопасности, особенно если вам необходимо передавать персонализированный ключ API в каждом запросе).
    • Убедитесь, что вы не инициируете предполетный запрос, который вам не нужен. API может предоставлять разрешение для простых запросов, но не для предварительных запросов.
  • Если ничего из вышеперечисленного не применимо: вместо этого попросите браузер взаимодействовать с вашим сервером, а затем пусть ваш сервер получает данные с другого сервера и передает их. (Существуют также сторонние размещенные службы, которые прикрепляют заголовки CORS к общедоступным ресурсам, которые вы можете использовать).
Квентин
источник
Если я запустил локальную локальную сеть на веб-сервере и попытаюсь выполнить загрузку ajax с IP / URL-адреса, это будет работать? Я еще не пробовал. поскольку мой веб-сервер, возвращающий данные json, будет MCU
Ciasto piekarz
@Ciastopiekarz - применяются обычные правила того же происхождения / другого происхождения. Применяются обычные правила сетевой маршрутизации.
Квентин
25
Самый полный ответ, который я когда-либо читал, вместо ссылки на корс ..
pungggi
@Quentin - Вау! +1! Итак, что я должен понять, так это то, что если Алиса использует расширение CORS, сервер думает, что ее HTTP-вызовы не из javascript, а из расширения браузера, и обрабатывает его как обычный запрос того же происхождения?
snippetkid
@snippetkid - Нет. В обычном случае сервер будет отправлять заголовки CORS во всех ответах и ​​не заботится о том, откуда пришел запрос. Обозреватель несет ответственность за разрешение или запрет доступа к данным JS на основе заголовков CORS в ответе. (Когда дело доходит до предполетных запросов, на сервере все становится / немного / сложнее)
Квентин
3

На целевом сервере должен быть разрешен запрос из разных источников. Чтобы разрешить это через экспресс, просто обработайте запрос параметров 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);
});
Дафок
источник
3

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

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

Вы можете использовать простые запросы .
Для выполнения «простых запросов» запрос должен соответствовать нескольким условиям. Например , только что позволяет POST, GETи HEADметод, а также позволяя лишь некоторые заголовки заданного (вы можете найти все условия здесь ).

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

zwif
источник
2

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

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

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

Как заставить работать почтовый запрос на совместное использование ресурсов (CORS)

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

Вишну
источник
0

Эта проблема CORS дополнительно не прорабатывалась (по другим причинам).

У меня сейчас эта проблема по другой причине. Мой интерфейс также возвращает ошибку заголовка Access-Control-Allow-Origin.

Просто я указал неправильный URL-адрес, поэтому этот заголовок не был отражен должным образом (в чем я предполагал, что это так). localhost (внешний интерфейс) -> вызов незащищенного http (предполагается, что это https), убедитесь, что конечная точка API из внешнего интерфейса указывает на правильный протокол.

morph85
источник
0

У меня такая же ошибка в консоли Chrome.

Моя проблема заключалась в том, что я пытался зайти на сайт, используя http://вместо https://. Так что поправлять было нечего, просто нужно было зайти на тот же сайт, используя https.

Субхаши
источник
0

Этот баг обошелся мне в 2 дня. Я проверил свой журнал сервера, запрос / ответ Preflight Option между браузером Chrome / Edge и сервером был в порядке. Основная причина в том, что ответ сервера GET / POST / PUT / DELETE для XHTMLRequest также должен иметь следующий заголовок:

access-control-allow-origin: origin  

"origin" находится в заголовке запроса (браузер добавит его в запрос за вас). например:

Origin: http://localhost:4221

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

access-control-allow-origin: *  

или заголовок ответа для конкретного запроса, например:

access-control-allow-origin: http://localhost:4221 

Сообщение в браузерах непонятно: "... Запрошенный ресурс"

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

HungNM2
источник
-1

Запрос «Получить» с добавлением заголовков преобразуется в запрос «Параметры». Так возникают проблемы с политикой Cors. Вы должны реализовать запрос «Параметры» на своем сервере.

кира
источник
-6

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

Перостек Бальведа
источник