Как работает 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
- Определите на каком
Origin
находится исходный веб сайт и настройте сервер, чтобы он присылал заголовокAccess-Control-Allow-Origin
со значением вашегоOrigin
в ответ. - Определите какие не простые
HTTP
методы будут использоваться и настройте сервер, чтобы он присылал заголовокAccess-Control-Allow-Methods
со значением имен этих методов в ответ. - Определите какие не простые
HTTP
заголовки будут использоваться и настройте сервер, чтобы он присылал заголовокAccess-Control-Allow-Headers
со значением имен этих заголовков в ответ.