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


111

tl; dr; Про ту саму політику щодо походження

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

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

Що заважає мені отримувати доступ до сторінки?


Я працюю на веб-сайті, і це було добре п'ять хвилин тому.
Пітер Девід Картер

1
чи видає заголовки CORS? можливо, якщо ви поділилися яким-небудь кодом, було б простіше побачити
Jaromanda X

Ймовірно. До якого відділу слід звернутися, щоб дізнатися? Я здебільшого займаюся основою мамарінет ...
Пітер Девід Картер

Так. Я вважаю, що організація департаментів все одно не є рівномірною, тому це, можливо, неясне питання, але я хотів би дізнатися трохи про те, що стосуються бекенда / маршрутизації / sys-admin у моїй компанії, і це здавалося гарним приводом для ознайомлення Я сам, якщо в майбутньому будуть проблеми, я можу допомогти.
Пітер Девід Картер

Я б попросив когось із боку сервера всередині вашої операції. Вони, мабуть, змінили його на вас, якщо ви раніше мали можливість отримати доступ до нього.
Ларрі Лейн

Відповіді:


205

tl; dr - у кінці підсумків та заголовки у відповіді, щоб полегшити пошук відповідних частин. Читати все рекомендується, хоча це дає корисну основу для розуміння того, чому це полегшує бачення того, як застосовується в різних обставинах.

Про ту саму політику щодо походження

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

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

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

Стандартний сценарій, що демонструє потребу в SOP, може бути продемонстрований трьома символами :

  • Аліса - людина з веб-браузером
  • Боб запускає веб-сайт ( https://www.[website].com/у вашому прикладі)
  • Mallory запускає веб-сайт ( http://localhost:4300у вашому прикладі)

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

Аліса відвідує веб-сайт Mallory, який має деякий JavaScript, який змушує браузер Аліси запитувати HTTP-запит на веб-сайт Боба (з її IP-адреси з її cookie тощо). Це може бути таким же простим, як використання XMLHttpRequestта читання програми responseText.

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


Чому та сама політика щодо походження застосовується, якщо ви не вважаєте, що вона повинна

Для будь-якої заданої URL-адреси можливо, що SOP не потрібен. Кілька поширених сценаріїв, коли це так:

  • Аліса, Боб і Меллорі - одна і та ж людина.
  • Боб надає повністю публічну інформацію

… Але браузер не має можливості знати, чи є одне з перерахованих вище правдивим, тому довіра не є автоматичною і застосовується SOP. Дозвіл повинен бути наданий явно до того, як браузер надасть дані, отримані на іншому веб-сайті.


Чому така ж політика щодо оригіналу застосовується лише до JavaScript на веб-сторінці

Розширення браузера *, вкладка "Мережа" в інструментах для розробників браузера та додатках, таких як Postman, встановлено програмне забезпечення. Вони не передають дані з одного веб-сайту на JavaScript, що належить іншому веб-сайту лише тому, що ви відвідали цей інший веб-сайт . Встановлення програмного забезпечення зазвичай займає більш свідомий вибір.

Не існує третьої сторони (Маллорі), яка вважається ризиком.

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


Чому ви можете відображати дані на сторінці, не читаючи їх за допомогою JS

Існує ряд обставин, коли сайт Mallory може змусити браузер отримувати дані від третьої сторони та відображати їх (наприклад, додаючи <img>елемент для відображення зображення). Однак JavaScript Mallory не може зчитувати дані цього ресурсу, але це може робити лише браузер Аліси та сервер Боба, тому це все ще захищено.


CORS

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

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

Access-Control-Allow-Origin: *

… У заголовках відповідей дозволити будь-якому веб-сайту читати дані.

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

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

Особливості того, як Боб встановлює цей заголовок відповіді, залежать від HTTP-сервера та / або мови програмування на стороні сервера. Існує колекція посібників для різних поширених конфігурацій, які можуть допомогти.

Модель застосування правил CORS

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


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

  • Дані не були приватними або
  • Маллорі довіряли

Але я не Боб!

Не існує стандартного механізму для додавання цього заголовка Меллорі, оскільки він має надходити з веб-сайту Боба, який вона не контролює.

Якщо у Боб працює загальнодоступний API, можливо, існує механізм увімкнення CORS (можливо, шляхом форматування запиту певним чином, або параметр конфігурації після входу на веб-сайт порталу розробників для сайту Боба). Це, мабуть, буде механізмом, реалізованим Боб. Меллорі могла прочитати документацію на сайті Боба, щоб побачити, чи щось є, або вона могла б поговорити з Боб і попросити його запровадити CORS.


Повідомлення про помилки, в яких згадується "Відповідь за передполіт"

Деякі запити перехресного походження попередньо висвітлюються .

Це відбувається, коли (грубо кажучи) ви намагаєтеся зробити запит перехресного походження, який:

  • Включає облікові дані, як куки
  • Неможливо створити звичайну форму HTML (наприклад, має власні заголовки або тип вмісту, який ви не можете використовувати у формах enctype).

Якщо ви правильно робите щось, що потребує попереднього польоту

У цих випадках тоді решта цієї відповіді все-таки застосовується, але вам також потрібно переконатися, що сервер може прослухати запит перед польотом (який буде OPTIONS(а не GET, POSTабо все, що ви намагалися надіслати), і відповісти на нього правом Access-Control-Allow-Originзаголовок , але також 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 на веб-сторінці", ви можете уникнути SOP, не записуючи 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
Найповніша відповідь, яку я коли-небудь читав, а не лише посилання про
корси

@Quentin - Нічого собі! +1! Тож, що я повинен розуміти, якщо Аліса використовує розширення CORS, сервер вважає, що її http-дзвінки відбуваються не з JavaScript, а з розширення браузера, і трактує це як звичайний той самий запит на походження?
snippetkid

@snippetkid - Ні. У звичайному випадку сервер надсилатиме заголовки CORS у відповідь і не хвилює, звідки надходив запит. Браузер зобов'язаний дозволити або заборонити доступ до даних до СВ на основі заголовків 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.


2

Це відбувається через помилку CORS. CORS розшифровується як спільний розподіл ресурсів. Простими словами, ця помилка виникає, коли ми намагаємося отримати доступ до домену / ресурсу з іншого домену.

Детальніше про це читайте тут: помилка CORS з jquery

Щоб виправити це, якщо у вас є доступ до іншого домену, вам доведеться дозволити Access-Control-Allow-Origin на сервері. Це можна додати в заголовки. Ви можете ввімкнути це для всіх запитів / доменів або певного домену.

Як запрацювати запит на обмін ресурсами між походженнями (CORS)

Ці посилання можуть допомогти


0

Ця проблема CORS не була детально розроблена (з інших причин).

У мене зараз ця проблема під іншою причиною. Мій передній кінець також повертає помилку заголовка "Access-Control-Allow-Origin".

Тільки що я вказав неправильну URL-адресу, щоб цей заголовок не відображався належним чином (у чому я вважаю, що він це робив). localhost (передній кінець) -> виклик незахищеного http (передбачається, що це https), переконайтеся, що кінцева точка API від переднього кінця спрямована на правильний протокол.


0

Я отримав таку ж помилку в консолі Chrome.

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


-1

Запит "Отримати" із доданими заголовками перетворюється на запит "Параметри". Так виникають проблеми з політикою Корса. Ви повинні реалізувати запит "Параметри" на своєму сервері.


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.