﻿# Cross\-Origin Resource Sharing \(CORS\)

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

Современные браузеры по умолчанию не разрешают веб\-страницам получать доступ к содержимому ответа, если запрос был отправлен на сервер по порту, домену или протоколу, отличающемуся от порта, домена или протокола самой страницы\. Данное правило безопасности называется **Same\-Origin Policy \(SOP\)**\. Такая политика была введена с целью предотвращения атак, связанных с несанкционированным доступом к различным ресурсам сайта\.

Однако в современном мире web\-технологий ситуация, при которой страница отправляет запросы к серверам с другим доменом, довольно частая\. Для того, чтобы её грамотно регламентировать, как раз и была создана технология CORS\. Она контролирует доступ к содержимому ответа, пришедшему с другого источника, либо сам факт отправки запроса\. 

Контроль осуществляется через чтение браузером заголовков ответа сервера\. Если сервер не прислал в ответе специальные CORS\-заголовки с требуемыми значениями, браузер либо не предоставляет странице содержимое ответа сервера, либо блокирует отправку запроса\. 

Существуют следующие основные CORS\-заголовки:

* `Access-Control-Allow-Origin` — определяет, какому источнику разрешено получать содержимое ответа сервера в рамках кросс\-доменного запроса\. В случае, если ответ сервера не будет содержать заголовка `Access-Control-Allow-Origin` со значением источника, откуда кросс\-доменный запрос был отправлен, отправка основного запроса блокируется, или содержимое ответа не предоставляется странице\.
* `Access-Control-Allow-Credentials` — определяет, допустимы ли в рамках кросс\-доменных запросов `credentials` \(например, cookies\)\. Если в запросе передаются cookies пользователя, а значением `Access-Control-Allow-Credentials` будет `false`, отправка основного запроса блокируется, или содержимое ответа не предоставляется странице\.
* `Access-Control-Allow-Methods` — определяет, какие методы допустимы в рамках кросс\-доменных запросов\. В случае, если в ответе на предварительный запрос в этом заголовке не будет указан метод основного запроса, его отправка блокируется\.
* `Access-Control-Allow-Headers` — определяет, какие заголовки допустимы в рамках кросс\-доменного запроса\. В случае, если в основном запросе будет присутствовать заголовок, который не указан в `Access-Control-Allow-Headers`, его отправка блокируется\.

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

Далее приведены простые сценарии осуществления обоих типов запросов\.

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

Запрос считается простым, если:

* используется метод: `GET`, `HEAD`, `POST`;
* содержит допустимые заголовки: `Accept`, `Accept-Language`, `Content-Language`, `Content-Type`, `Range`;
* заголовок `Content-Type` содержит одно из следующих значений: `application/x-www-form-urlencoded`, `multipart/form-data`, `text/plain`;

Смоделируем ситуацию, в которой мы отправляем`GET`\-запрос, содержащий заголовок `Content-Type` со значением `text/plain`\. Отправляться запрос будет со страницы `http://localhost:4000` на сервер, находящийся по адресу `http://localhost:4001`\. 

Запрос будет отправлен, и ответ придёт\. Статус у ответа будет успешным\. Но в связи с тем, что порты у веб\-страницы и у сервера разные, **Same\-Origin Policy** они не удовлетворят\. И, как следствие, сам браузер не предоставит странице доступ к содержимому ответа\.

Чтобы позволить странице получить доступ к содержимому ответа, сервер должен вернуть правильный CORS\-заголовок `Access-Control-Allow-Origin` со значением `http://localhost:4000`\. В этом случае браузер предоставит нашей странице содержимое ответа\.

В случае, если в запросе отправлялись какие\-либо `credentials` \(к примеру, cookies или TLS сертификаты\), а в ответе сервера не будет заголовка `Access-Control-Allow-Credentials` со значением `true`, браузер не предоставит странице доступ к содержимому ответа\.

## Предварительные запросы

В случае, если отправляемый запрос не удовлетворяет какое\-либо из условий простого запроса, перед его отправкой на сервер браузер отправит preflight\-запрос\. 

К примеру, заменим в нашем запросе метод `GET` на метод `DELETE`\. В этом случае браузер поступит иначе\. Серверу перед основным запросом будет отправлен preflight\-запрос с методом `OPTIONS`\. Он будет содержать информацию о нашем основном запросе: его метод, адрес веб\-страницы, с которой он был отправлен, его заголовки\.

В ответ браузер ожидает получить нужные CORS\-заголовки\. Однако здесь есть одно важное отличие: в случае, если ответ на preflight\-запрос "не удовлетворит" браузер, основной запрос отправлен не будет\. 

Так же, как и в нашем предыдущем примере, мы ожидаем увидеть в ответе на preflight\-запрос заголовок `Access-Control-Allow-Origin` со значением `http://localhost:4000`\. 

Помимо него важную роль играют и другие CORS\-заголовки\. К примеру, если заголовок `Access-Control-Allow-Methods` не будет содержать значения `DELETE`, основной запрос также не будет отправлен\.

## Принцип минимальных привилегий

Важно рассказать про один фундаментальный момент в контексте CORS\. Заголовок `Access-Control-Allow-Origin`, помимо конкретного хоста, может принимать значение `*` \(wildcard\)\. Оно разрешает хосту абсолютно любого происхождения просматривать содержимое ответа сервера\. Это может быть нежелательным поведением, особенно если изначально предполагалось, что эти ресурсы должны предоставляться лишь веб\-странице с определённым доменом\. 

То же самое касается и заголовка `Access-Control-Allow-Credentials` со значением `true`\. С ним нужно быть очень аккуратным, особенно если значение для заголовка `Access-Control-Allow-Origin` на сервере генерируется динамически, а не берётся из "белого списка"\. Это может открыть достаточно большое пространство для уязвимостей\.

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

* раскрытие приватных данных при выходе из корпоративной сети во внешнее интернет\-пространство;
* злоумышленники смогут выдавать API вашего приложения за свой;
* в случае, если сайт подвержен XSS, последствия атаки могут быть более серьёзными\.

Поэтому, если приложение развёрнуто не в тестовой среде или не подразумевается, что оно представляет собой публичный API, заголовок `Access-Control-Allow-Origin` должен определяться конкретным значением из "белого списка"\.

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

* [OWASP\. Testing Cross Origin Resource Sharing\.](https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/11-Client-side_Testing/07-Testing_Cross_Origin_Resource_Sharing)
* [PortSwigger\. Vulnerabilities arising from CORS configuration issues\.](https://portswigger.net/web-security/cors#vulnerabilities-arising-from-cors-configuration-issues)
* [PortSwigger\. Exploiting CORS misconfigurations for Bitcoins and bounties\.](https://portswigger.net/research/exploiting-cors-misconfigurations-for-bitcoins-and-bounties)

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

* [Mozilla\. Cross\-Origin Resource Sharing \(CORS\)\.](https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS)
* [Mozilla\. Same\-origin policy\.](https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy)
* [OWASP Cheat Sheet Series\. HTML5 Security Cheat Sheet\. Cross Origin Resource Sharing\.](https://cheatsheetseries.owasp.org/cheatsheets/HTML5_Security_Cheat_Sheet.html#cross-origin-resource-sharing)