Cross-origin resource sharing (cors)

Контроль безопасности

Кросс-доменные запросы проходят специальный контроль безопасности, цель которого – не дать злым хакерам завоевать интернет.

Серьёзно. Разработчики стандарта предусмотрели все заслоны, чтобы «злой хакер» не смог, воспользовавшись новым стандартом, сделать что-то принципиально отличное от того, что и так мог раньше и, таким образом, «сломать» какой-нибудь сервер, работающий по-старому стандарту и не ожидающий ничего принципиально нового.

Давайте, на минуточку, вообразим, что появился стандарт, который даёт, без ограничений, возможность делать любой странице HTTP-запросы куда угодно, какие угодно.

Как сможет этим воспользоваться злой хакер?

Он сделает свой сайт, например и заманит туда посетителя (а может посетитель попадёт на «злонамеренную» страницу и по ошибке – не так важно). Когда посетитель зайдёт на , он автоматически запустит JS-скрипт на странице

Этот скрипт сделает HTTP-запрос на почтовый сервер, к примеру,. А ведь обычно HTTP-запросы идут с куками посетителя и другими авторизующими заголовками

Когда посетитель зайдёт на , он автоматически запустит JS-скрипт на странице. Этот скрипт сделает HTTP-запрос на почтовый сервер, к примеру, . А ведь обычно HTTP-запросы идут с куками посетителя и другими авторизующими заголовками.

Поэтому хакер сможет написать на код, который, сделав GET-запрос на , получит информацию из почтового ящика посетителя. Проанализирует её, сделает ещё пачку POST-запросов для отправки писем от имени посетителя. Затем настанет очередь онлайн-банка и так далее.

Спецификация CORS налагает специальные ограничения на запросы, которые призваны не допустить подобного апокалипсиса.

Запросы в ней делятся на два вида.

считаются запросы, если они удовлетворяют следующим двум условиям:

  1. : GET, POST или HEAD
  2. – только из списка:
  • со значением , или .

«Непростыми» считаются все остальные, например, запрос с методом или с заголовком не подходит под ограничения выше.

Принципиальная разница между ними заключается в том, что «простой» запрос можно сформировать и отправить на сервер и без XMLHttpRequest, например при помощи HTML-формы.

То есть, злой хакер на странице и до появления CORS мог отправить произвольный GET-запрос куда угодно. Например, если создать и добавить в документ элемент , то браузер сделает GET-запрос на этот URL.

Аналогично, злой хакер и ранее мог на своей странице объявить и, при помощи JavaScript, отправить HTML-форму с методом GET/POST и кодировкой . А значит, даже старый сервер наверняка предусматривает возможность таких атак и умеет от них защищаться.

А вот запросы с нестандартными заголовками или с методом таким образом не создать. Поэтому старый сервер может быть к ним не готов. Или, к примеру, он может полагать, что такие запросы веб-страница в принципе не умеет присылать, значит они пришли из привилегированного приложения, и дать им слишком много прав.

Поэтому при посылке «непростых» запросов нужно специальным образом спросить у сервера, согласен ли он в принципе на подобные кросс-доменные запросы или нет? И, если сервер не ответит, что согласен – значит, нет.

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

Cross-origin network access

The same-origin policy controls interactions between two different origins, such as when you use or an  element. These interactions are typically placed into three categories:

  • Cross-origin writes are typically allowed. Examples are links, redirects and form submissions. Certain rarely used HTTP requests require .
  • Cross-origin embedding is typically allowed. Examples are listed below.
  • Cross-origin reads are typically not allowed, but read access is often leaked by embedding. For example, you can read the width and height of an embedded image, the actions of an embedded script, or the availability of an embedded resource.

Here are some examples of resources which may be embedded cross-origin:

  • JavaScript with . Error messages for syntax errors are only available for same-origin scripts.
  • CSS with . Due to the relaxed syntax rules of CSS, cross-origin CSS requires a correct header. Restrictions vary by browser: IE, Firefox, Chrome, Safari (scroll down to CVE-2010-0051) and Opera.
  • Images with . Supported image formats include PNG, JPEG, GIF, BMP, SVG, …
  • Media files with and .
  • Plug-ins with , and .
  • Fonts with . Some browsers allow cross-origin fonts, others require same-origin fonts.
  • Anything with and . A site can use the header to prevent this form of cross-origin interaction.

Use CORS to allow cross-origin access.

  • To prevent cross-origin writes, check for an unguessable token in the request, known as a Cross-Site Request Forgery (CSRF) token. You must prevent cross-origin reads of pages that know this token.
  • To prevent cross-origin reads of a resource, ensure that it is not embeddable. It is often necessary to prevent embedding because embedding a resource always leaks some information about it.
  • To prevent cross-origin embedding, ensure that your resource cannot be interpreted as one of the embeddable formats listed above. The browser does not respect the in most cases. For example, if you point a tag at an HTML document, the browser will try to parse the HTML as JavaScript. When your resource is not an entry point to your site, you can also use a CSRF token to prevent embedding.

Запрос нашего API через AJAX из других доменов

И допустим у нас есть какое-нибудь клиентское приложение работающее с нашим API. Но учтем что, наше API находится по адресу http://127.0.0.1:3000/public, а наш клиент размещен на http://127.0.0.1:8000, и на клиенте есть следующий код:

fetch('http://127.0.0.1:3000/public')
  .then(response => response.text())
  .then((result) => {
    document.body.textContent = result
  })

И это не будет работать!

Если мы посмотрим на вкладку network в консоле Хрома при обращение c http://127.0.0.1:8000 к http://127.0.0.1:3000 то там не будет ошибок:

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

Ага! Нам не хватает заголовка Access-Control-Allow-Origin. Но зачем он нам и для чего он вообще нужен?

2 ответа

1

Лучший ответ

если вы, ребята, используете chrome, попробуйте это расширение https://chrome.google.com/webstore/detail/requestly-redirect-url-mo/mdnleldcmiljblolnjpnblkcekpdkpa

вы можете изменять запросы «на лету», даже заголовки

17 май 2017, в 12:34
Поделиться

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

Это простое решение, которое будет переноситься на разные серверы. На стороне AJAX все, что вам нужно, это изменить имя хоста на localhost или IP вашего тестового прокси-сервера.

17 май 2017, в 11:56
Поделиться

Ещё вопросы

  • Какой самый эффективный способ разбить строку текста в C ++?
  • индикатор загрузки автозаполнения
  • Загрузка локальных данных на сервер / верстак сообщества mysql
  • 1перекрестная идентификация (перекрытие) двух списков в Python по общему идентификатору
  • 2Метод OnRender не работает с более чем 144 элементами управления
  • Данные зависимые тесты
  • PHP | SQL — mysqli_stmt_prepare не удается и подключен к базе данных
  • 2Кнопка включения / выключения WPF на основе элемента проверки в ItemsControl
  • 1Мои коды Python в целом очень медленные, это нормально?
  • Как я могу проверить $ watch в Angular
  • 1Проблемы с ротацией телефонов Android в приложении phoneGap
  • Ограничить ввод только цифрами
  • AngularJS множественное включение
  • Angularjs нг-шоу не работает при нажатии
  • jQuery показывает загрузочную картинку при загрузке GIF
  • 1Плагин Maven — редактировать файлы в цель (война)
  • 1Как оптимизировать и найти коэффициенты для двух уравнений одновременно в Python 2.7?
  • Как определить идентификатор устройства из SERVICE_CONTROL_DEVICEEVENT
  • 1Как обрабатывать события на несколько уровней, Java
  • 1Версии defaultDeep и значения по умолчанию, которые переопределяют неопределенные и нулевые значения
  • Могу ли я переопределить разрешение параметров определенного состояния в AngularJS UI Router?
  • 1Использование очень больших растровых текстур с OPENGL 2.0 Android
  • Как сделать Sequelize $ между запросами?
  • Единственный класс CSS отказывается вести себя
  • C ++ аналог функции отображения
  • 1Как заставить Apache Spark mapPartition работать правильно?
  • изменить размер тега IMG по умолчанию с помощью CSS
  • две стороны куба скрыты после текстурирования в opengl
  • OpenGL комбинация розыгрышей
  • HTML и Javascript форма не работает
  • Youtube thumbnail + playicon для ссылок
  • 1Почему не удерживается CTRL-C и вызывается signal_handler?
  • 1Поиск корней с помощью scipy.optimize.root
  • Отфильтровать проблему в Angular
  • NodeJS MySQL соединение с несколькими запросами
  • 1В каком формате лучше всего анализировать файл Heapdump? Это hprof?
  • как создать столбец среднего номера всей таблицы
  • Фокус не работает в contenteditable div, когда генерируется динамически
  • Отображение выбранной опции
  • 2манипулировать простым калькулятором Windows с помощью Win32 API в C #?
  • 2Проблема Zedgraph Magnitude в X2Axis в vb.net или c #
  • В C ++, когда класс не находится в том же файле, что и основная подпрограмма, среда выполнения становится намного медленнее?
  • 1Преобразовать document.referrer как переменную в JSON
  • 2Создайте общий список в xaml 4.5+
  • Поведение Inject для элементов DOM в Blaze
  • Перезапись Angularjs и Apache не работает в подпапке
  • 1Эффективность при вставке в mongodb (пимонго)
  • 1Как программно подписать асинхронного потребителя на очередь в Spring AMQP?
  • У меня проблемы с созданием и выполнением функций-прототипов в программировании на C ++
  • как преобразовать целочисленную переменную в объект QTime

Зачем нужен CORS? Экскурс в историю

CORS существует для защиты интернета от злых хакеров.

Серьёзно. Давайте сделаем краткое историческое отступление.

Многие годы скрипт с одного сайта не мог получить доступ к содержимому другого сайта.

Это простое, но могучее правило было основой интернет-безопасности. Например, хакерский скрипт с сайта не мог получить доступ к почтовому ящику пользователя на сайте . И люди чувствовали себя спокойно.

В то время в JavaScript не было методов для сетевых запросов. Это был «игрушечный» язык для украшения веб-страниц.

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

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

Таким способом было возможно сделать GET/POST запрос к другому сайту даже без сетевых методов, так как формы можно отправлять куда угодно. Но так как запрещено получать доступ к содержимому с другого сайта, прочитать ответ было невозможно.

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

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

Если сайт, например , хотел предоставить данные для такого доступа, он предоставлял так называемый «протокол JSONP» (JSON with Padding)».

Вот как он работал.

Например, нам на нашем сайте нужны данные с сайта , скажем, погода:

  1. Сначала, заранее, объявляем глобальную функцию для обработки данных, например .

  2. Затем создаём тег с , при этом имя нашей функции – в URL-параметре .

  3. Удалённый сервер с должен в ответ сгенерировать скрипт, который вызывает с данными, которые хочет передать.

  4. Когда этот скрипт загрузится и выполнится, наша функция получает данные.

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

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

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

Пару слов о CSRF

Обратите внимание, что существует класс атак, называемый подделкой межсайтовых запросов (Cross Site Request Forgery – csrf ), от которых не защищает Same-Origin Policy. При CSRF-атаке злоумышленник отправляет запрос сторонней странице в фоновом режиме, например, отправляя POST запрос на веб-сайт вашего банка

Если у вас в этот момент есть действительный сеанс с вашим банком, любой веб-сайт может сгенерировать запрос в фоновом режиме, который будет выполнен, если ваш банк не использует контрмеры против CSRF

При CSRF-атаке злоумышленник отправляет запрос сторонней странице в фоновом режиме, например, отправляя POST запрос на веб-сайт вашего банка. Если у вас в этот момент есть действительный сеанс с вашим банком, любой веб-сайт может сгенерировать запрос в фоновом режиме, который будет выполнен, если ваш банк не использует контрмеры против CSRF.

Так же обратите внимание, что, несмотря на то, что действует Same-Origin Policy, наш пример запроса с сайта secondparty.com на сайте 127.0.0.1:3000 будет успешно выполнен – мы просто не соможем получить доступ к результатам. Но для CSRF нам не нужен результат …. Например, API, которое позволяет отправлять электронные письма, выполняя POST запрос, отправит электронное письмо, если мы предоставим ему правильные данные

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

Например, API, которое позволяет отправлять электронные письма, выполняя POST запрос, отправит электронное письмо, если мы предоставим ему правильные данные. Злоумышленнику не нужно заботится о результате, его забота это отправляемое электронное письмо, которое он получит независимо от возможности видеть ответ от API.

Настройка CORS в Nginx

CORS (cross-origin resource sharing) — совместное использование ресурсов между разными источниками . Это спецификация, которая обеспечивает действительно открытый доступ между доменами. Если вы размещаете общедоступный контент, рассмотрите возможность использования CORS, чтобы открыть его для универсального доступа из JavaScript в браузерах.

До недавнего времени основным способом преодоления ограничений, наложенных в same-origin-policy относительно XSS запросов, было использование JSONP . Сам JSONP имеет неустранимое ограничение — позволяет только получение данных GET методом , то есть отправка данных через POST метод остается недоступной.

Почему CORS важен?

За последние годы JavaScript и веб-программирование активно развиваются, но same-origin политику никто не отменял. Это препятствует тому, чтобы JavaScript делал запросы между разными доменами, что породило различные хаки для выполнения междоменных запросов.

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

Правило ограничения домена (Same Origin Policy, Принцип одинакового источника) — это важная концепция безопасности для некоторых языков программирования на стороне клиента, таких как JavaScript. Политика разрешает сценариям, находящимся на страницах одного сайта, доступ к методам и свойствам друг друга без ограничений, но предотвращает доступ к большинству методов и свойств для страниц на разных сайтах. Одинаковые источники — это источники, у которых совпадают три признака: домен, порт и протокол.

Концепция правила ограничения домена появилась во времена Netscape Navigator 2.0. Скрытые производные оригинальной разработки используются во всех современных браузерах, а также в плагинах, таких как Adobe Flash либо для механизмов отличных от DOM манипуляций, таких как XMLHttpRequest.

Как это работает?

ля инициации Cross-origin запроса браузер клиента добавляет в HTTP запрос Origin (домен сайта, с которого происходит запрос). Например страница http://www.a.com/page.html пытается получить данные со страницы http://www.b.com/cors.txt. В случае если браузер клиента поддерживает технологию CORS, запрос будет выглядеть так:

Если сервер www.b.com хочет разрешить получение данных с www.a.com то в ответе сервера будет присутствовать строчка:

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

В случае, если сервер хочет разрешить доступ любому домену, он может указать в ответе:

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

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

Пример конфигурации CORS для web-сервера Nginx

Nginx — легковесный, по сравнению с Apache, HTTP, обратный прокси сервер написанный Igor Sysoe. Официальную документацию к Nginx вы найдете здесь.…

Как регламентировать перекуры в течение рабочего дня? Можно ли разрешать опаздывать к началу рабочего дня? Можно ли чатится во время…

iReadMail пожалуй один единственный почтовый сервер, установку которого запустил и все произошло само собой. Единственное что вам необходимо — только…

Ответ 1

Access-Control-Allow-Headers не допускает «*» приемлемого значения.

Вместо звездочки следует отправлять принятые заголовки (сначала X-Requested-With, как указано в ошибке).

Согласно MDN Web Docs 2021

Значение «*» считается специальным подстановочным знаком только для запросов без учетных данных (запросы без файлов cookie HTTP или информации аутентификации HTTP). В запросах с учетными данными оно рассматривается как буквальное имя заголовка «*» без специальной семантики. Обратите внимание, что заголовок авторизации не может содержать подстановочные знаки и всегда должен быть указан явно

4 ответа

Лучший ответ

Веб-страницы не могут изменить заголовок источника, но расширения могут изменять заголовки запроса с помощью chrome.webRequest API , Но и не поддерживаются этим API, так что это не поможет, если сервер также не поддерживает другие средства связи через http (s) (например, длинный опрос).

Тем не менее, есть решение: просто загрузите (известную) веб-страницу в желаемом источнике в iframe (например, или ) и используйте скрипт содержимого, чтобы открыть оттуда WebSocket.

12

Rob W
18 Май 2015 в 11:09

Это зависит от того, как вы хотите использовать свой браузер Chrome. Так как вы упомянули localhost, я предполагаю, что вы разрабатываете и будете использовать это для некоторой очистки. Я предлагаю вам изучить протокол Chrome DevTools, который сделает (почти) любой вид защиты бесполезным потому что вы используете настоящий браузер. CORS, Origin, Cookie или любое произвольное значение заголовка будут находиться под вашим контролем, и вы можете отправить собственный заголовок для запроса (запросов) xhr / websocket. Если вы хотите манипулировать более сложным способом, вы можете использовать Network.continueInterceptedRequest. Возможно, вы захотите запустить chrome только с помощью таких параметров, как «—disable-web-security, —disable-xss-auditor, —disable-client-side-phishing-Detection, —allow-insecure-localhost». параметры в peter.sh. Однако для последнего варианта требуется плагин, чтобы подделать исходный заголовок, поэтому я рекомендую первый вариант.

Gillsoft AB
2 Авг 2017 в 07:46

Насколько я знаю, это будет невозможно, это сломает охранников против CSRF в Chrome.

Если бы вы смогли сделать это, вся концепция XHR развалилась бы.

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

Посмотрите здесь, если вы хотите узнать больше об этом ,

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

1

Community
23 Май 2017 в 12:17

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

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

5

adriann
17 Май 2015 в 20:50

Обзор функциональности

Стандарт Cross-Origin Resource Sharing работает с помощью добавления новых HTTP-заголовков, которые позволяют серверам описывать набор источников, которым разрешено читать информацию, запрашиваемую web-браузером. В частности, для методов HTTP-запросов, которые могут привести к побочным эффектам над данными сервера (в частности, для HTTP методов, отличных от  или для запросов, использующих определённые MIME-типы), спецификация требует, чтобы браузеры «предпроверяли» запрос, запрашивая поддерживающие методы с сервера с помощью метода HTTP-запроса  и затем, поверх «подтверждения» с сервера, отсылали фактический запрос с фактическим методом HTTP-запроса. Сервера также могут оповещать клиентов должны ли «полномочия» (включая Cookies и HTTP Authentication данные) быть отправлены с запросом.

Следующая секция описывает сценарии, а также предоставляет анализ использования HTTP-заголовков. 

Ответ 3

Многие описания не упоминают, что элементовAccess-Control-Allow-Origin недостаточно. Вот полный пример, который мне подходит:

<?php

    if ($_SERVER === ‘OPTIONS’) {

        header(‘Access-Control-Allow-Origin: *’);

        header(‘Access-Control-Allow-Methods: POST, GET, DELETE, PUT, PATCH, OPTIONS’);

        header(‘Access-Control-Allow-Headers: token, Content-Type’);

        header(‘Access-Control-Max-Age: 1728000’);

        header(‘Content-Length: 0’);

        header(‘Content-Type: text/plain’);

        die();

    }

    header(‘Access-Control-Allow-Origin: *’);

    header(‘Content-Type: application/json’);

    $ret = [

        ‘result’ => ‘OK’,

    ];

    print json_encode($ret);

Заключение

В этой статье мы рассмотрели Same-Origin Policy и то, как мы можем использовать CORS, чтобы разрешать запросы между источниками, когда это необходимо.

Это требует настройки на стороне сервера и на стороне клиента и в зависимости от запроса вызовет предварительный (preflight) запрос.

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

Выводы

Браузер использует Same-origin policy, чтобы не обрабатывать AJAX ответы от веб-сайтов расположенных на адресах отличных от адреса с которого была загружена веб страница.

Same-origin policy не запрещает генерировать запросы к другим сайтам, но запрещает обрабатывать от них ответ.

CORS (Cross-Origin Resource Sharing) механизм, который использует дополнительные заголовки HTTP, чтобы дать браузерам указание предоставить веб-приложению, работающему в одном источнике, доступ к ответу на запрос к ресурсам из другого источника

CORS вместе с credentials (с данными аутентификации) требует осторожности.

CORS это браузерная политика. Другие приложения не затрагиваются этим понятием.

Cross-Origin Resource Sharing (CORS)Martin Splitt — Understanding CORS

Spread the love

7
Поделились

Рейтинг
( Пока оценок нет )
Понравилась статья? Поделиться с друзьями:
Все про сервера
Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: