Howtojs

Как работает Cross-Origin Resource Sharing?

16 февраля 2021 г. • ☕️ 6 мин.

CORS

Cross-Origin Resource Sharing или CORS - проблема с которой встречаются большинство веб-разработчиков.

Представим, мы загрузили HTML страницу по адресу https://cats.com, внутри которой есть тэг img ссылающийся на картинку https://dogs.com/image.jpg. Такой запрос пройдет успешно так же и для загрузки ресурсов различного типа: CSS, images и scripts.

Мы декларативно ссылаемся на ресурс, говоря браузеру: загрузи это для нас. Браузер делает HTTP запрос и загружает ресурс.

Same-Origin Policy

Что на счет запросов, которые мы делаем из наших скриптов с помощью XMLHttpRequest или Fetch? Для безопасности, браузер ограничивает доступ к ресурсам с других Origin. XMLHttpRequest или Fetch могут отправить запрос только на свой Origin.

Origin

Origin - это комбинация из домена, порта и схемы протокола.

  • https://cats.com
  • http://cats.com
  • https://cats.com:8080
  • https://dogs.com
  • https://api.cats.com

Все это разные Origin.

Что значит “для безопасности”?

Все сводится к Cookie.

Представим, мы пользуемся банком https://mybank.com. Для аутентификации пользователя банк установил свои Cookie на домен mybank.com в браузер. Когда браузер делает запрос на домен mybank.com, он добавляет Cookie в запрос, чтобы сервер мог нас узнать.

Значит запрос на https://mybank.com с нашими Cookie может совершить платеж от нашего имени или данные карты.

Представим, мы зашли на сайт https://isteelyourmoney.com, этот сайт сделает XMLHttpRequest или Fetch запрос без нашего ведома на https://mybank.com/pay и браузер автоматически добавит наши Cookie к запросу. Так мы можем потерять деньги, даже не заметив этого.

Как это сделать безопасным?

  • Почему бы не блокировать запросы на “не родной” Origin?
  • Как разрешить запросы на “не родной” Origin, когда нам это явно нужно?

Так появился CORS.

Cross-Origin Resource Sharing (CORS)

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

Стандарт CORS описывает специальные HTTP headers заголовки, которые позволяют браузеру запросить ресурс при помощи XMLHttpRequest или Fetch, только в том случае, если есть разрешение.

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

Access-Control-Allow-Origin

Один из заголовков, необходимых для доступа к ресурсам на “не родном” Origin является Access-Control-Allow-Origin.

Каждый раз, когда с сайта https://cats.com отправляется XMLHttpRequest или Fetch запрос на https://dogs.com, сервер должен включить в ответ заголовок Access-Control-Allow-Origin cо значением https://cats.com.

например:

Access-Control-Allow-Origin: https://cats.com

В случае если такого заголовка не будет, то браузер не даст нам прочитать ответ, сообщив об ошибке.

Non-simple requests (Не простые запросы)

Заголовка Access-Control-Allow-Origin хватает для простых запросов. Что же такое простые и не простые запросы?

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

  • запросы использующие методы

    • GET
    • POST
  • запросы использующие заголовки

    • Accept
    • Accept-Language
    • Content-Language
    • Content-Type со значениями (application/x-www-form-urlencoded, multipart/form-data или text/plain)

Все остальные запросы “не простые”.

Preflight OPTIONS request

Перед отправкой такого запроса, браузер сначала посылает специальный preflight “предзапрос” OPTIONS для подтверждения того, что сервер примет “не простой” запрос.

Заголовки для non-simple request

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

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

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

OPTIONS /page HTTP/1.1
Origin: https://cats.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: Content-Type

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

Access-Control-Allow-Origin: https://cats.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: Content-Type

После ответа на preflight запрос OPTIONS, браузер пошлет оригинальный запрос, как простой запрос.

Практические шаги для базовой настройки CORS

  1. Определите на каком Origin находится исходный веб сайт и настройте сервер, чтобы он присылал заголовок Access-Control-Allow-Origin со значением вашего Origin в ответ.
  2. Определите какие не простые HTTP методы будут использоваться и настройте сервер, чтобы он присылал заголовок Access-Control-Allow-Methods со значением имен этих методов в ответ.
  3. Определите какие не простые HTTP заголовки будут использоваться и настройте сервер, чтобы он присылал заголовок Access-Control-Allow-Headers со значением имен этих заголовков в ответ.