Глоссарий

Что такое CORS — как он работает и что открывает неправильная настройка

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

Опубликовано 2026-06-11 Обновлено 2026-10-06 6 мин чтения
На этой странице

API, который заработал после добавления Access-Control-Allow-Origin, не обязательно безопасен. CORS нельзя добавить один раз и забыть; важно сузить, кому вы разрешаете. Разберём, как он работает и как настроить его безопасно (без шагов атаки).

Сначала о том, как это работает

Браузеры применяют политику одного источника: JS другого источника не может свободно читать ответы другого сайта. CORS существует, чтобы открыть это исключение только тем, кому сервер явно разрешает.

Источник (origin) — это сочетание схемы (https), имени хоста и порта. У https://example.com и https://api.example.com разные хосты, значит, это разные источники; у http://example.com и https://example.com разные схемы, значит, они тоже разные.

Заголовок ответаЗначение
Access-Control-Allow-OriginКаким источникам можно читать ответ
Access-Control-Allow-CredentialsРазрешены ли запросы с учётными данными (куками)
Access-Control-Allow-Methods / -HeadersКакие HTTP-методы/заголовки разрешены

Суть: CORS находится на стороне «ослабления ограничения». Ослабьте его неверно — и данные, которые не должны быть читаемы, становятся читаемыми для третьих сторон.

Важно и ещё одно: CORS останавливает именно чтение ответа JavaScript. Простой запрос доходит до сервера и обрабатывается даже без разрешения CORS. В случаях вроде пользовательских заголовков браузер сначала проверяет запросом OPTIONS (preflight) и не отправляет настоящий запрос, если это не разрешено.

Чем он отличается от похожих механизмов

CORS часто путают с механизмами с похожими названиями и с близкой уязвимостью.

ТерминЧто определяетКто обеспечивает
Политика одного источникаДругие источники не могут читать ответы (поведение браузера по умолчанию)Браузер
CORSКаким источникам, в виде исключения, можно читатьСервер объявляет, браузер обеспечивает
CSRFАтака, заставляющая браузер вошедшего пользователя отправлять непреднамеренные запросыПредотвращается CSRF-токенами и SameSite
CSPКакие скрипты и соединения может загружать ваша собственная страницаСервер объявляет, браузер обеспечивает

CORS — о том, «можно ли прочитать ответ»; CSRF — о том, «можно ли отправить запрос от имени пользователя». Ужесточение CORS не предотвращает CSRF.

Что делает настройку опасной

Опасные настройки (частые)

  • Отражение Origin запроса обратно как разрешённого
  • Access-Control-Allow-Origin: * плюс разрешение учётных данных
  • Открытие API широко кросс-доменно, когда это не нужно

Безопасные настройки

  • Allowlist (только фиксированные доверенные источники)
  • Запрет по умолчанию для всего остального
  • Для запросов с учётными данными — конкретный источник, а не *
JS сайта злоумышленника запрашивает ваш API (пользователь вошёл в систему)
↓ сервер вслепую разрешает Origin (неправильная настройка)
браузер разрешает чтение ответа = персональные данные/токены попадают на сайт злоумышленника
При слабой настройке JS сайта злоумышленника может использовать активный сеанс пользователя, чтобы прочитать ответ API.

Как обычно возникают неправильные настройки

Большинство неправильных настроек появляется из попытки избавиться от ошибки CORS. Типичная последовательность:

  1. Вызов API с фронтенда с куками даёт ошибку CORS
  2. Вы добавляете Access-Control-Allow-Origin: *. Но для запросов с учётными данными браузер не даёт странице прочитать ответ с *, и ошибка остаётся
  3. Вы переходите на отражение пришедшего Origin, и ошибка исчезает. Одновременно любой сайт теперь может читать ответы с активным сеансом

Даже с allowlist небрежное сравнение ведёт туда же.

  • Сравнение «оканчивается на example.com» пропускает и другой домен, например evil-example.com
  • Сравнение «начинается с https://example.com» пропускает и https://example.com.evil.net
  • Разрешение источника null для удобства разработки разрешает и чтение из источников null, которые могут создать другие сайты

Сравнивайте источник целиком (схему, хост и порт) на точное совпадение.

Основы безопасной настройки

1

Используйте allowlist (самое важное)

Разрешайте только заранее определённые доверенные источники и запрещайте остальное (запрет по умолчанию). Не «разрешайте просто всё».
2

Не отражайте Origin вслепую

Не подставляйте Origin запроса прямиком в Access-Control-Allow-Origin. Возвращайте его только когда он совпадает с allowlist. Поскольку значение теперь зависит от запроса, отправляйте также Vary: Origin, чтобы кэши не путали ответы.
3

Никогда не используйте * с учётными данными

Не сочетайте Access-Control-Allow-Origin: * с Allow-Credentials: true. Вместо этого указывайте конкретный источник.
4

Минимизируйте то, что открываете

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

Как проверить свой сайт

Отправьте своему API запрос от имени другого источника и посмотрите на заголовки ответа. Делайте это только с API, которыми вы управляете.

# Указываем источник, который вы не разрешали, и смотрим только заголовки ответа
curl -s -o /dev/null -D - -H "Origin: https://example.com" https://your-api.example/ | grep -i "^access-control"
  • Если приходит Access-Control-Allow-Origin: https://example.com, API отражает Origin. Добавьте сверку с allowlist
  • Если одновременно есть Access-Control-Allow-Origin: * и Access-Control-Allow-Credentials: true, пересмотрите настройку
  • Если ничего не приходит или приходит только источник вашего фронтенда, всё в порядке

Повторите ту же проверку с Origin: null. Для сайта, владение которым вы подтвердили, аудит безопасности сайта проверяет отражение источника и настройки учётных данных вместе. Остальные заголовки безопасности можно проверить проверщиком заголовков безопасности.

Мнение этого сайта: CORS — это «как ослабляешь», а не «защита» — сужайте, кому открываете

Частое заблуждение — «добавление заголовков CORS делает безопасно». Всё наоборот: CORS ослабляет ограничение браузера. Поэтому важно не то, «как добавить», а то, чтобы «минимизировать, кому и насколько широко открываешь». На этом сайте мы отделяем данные, которые можно читать извне, от тех, которые нельзя, и рекомендуем запрет по умолчанию с allowlist, открывающим только исключения. Заметьте, что XSS (который ломает предпосылку о чтении) и CSRF (который нацелен на изменения состояния) — это отдельные уязвимости: один лишь CORS не покрывает всё.

Источники (первичные)

  • MDN Web Docs, «Cross-Origin Resource Sharing (CORS)» — developer.mozilla.org (запрет * для запросов с учётными данными, условия preflight, Vary: Origin)
  • WHATWG Fetch Standard, «CORS protocol» — fetch.spec.whatwg.org
  • OWASP HTML5 Security Cheat Sheet — cheatsheetseries.owasp.org (разрешать только доверенные домены; не возвращать заголовок Origin без проверки)
  • PortSwigger Web Security Academy, «Cross-origin resource sharing (CORS)» — portswigger.net (ошибки сверки с allowlist, источник null, CORS — не защита от CSRF)
  • MITRE CWE-942: Permissive Cross-domain Policy with Untrusted Domains — cwe.mitre.org

Читать дальше

Классификация

CWE классифицирует типы слабостей, из-за которых возникают уязвимости; MITRE ATT&CK классифицирует техники атакующих. Обе системы ведёт MITRE, и они широко используются для разметки уязвимостей и правил обнаружения.

CWE™: Copyright © 2006–2026, The MITRE Corporation. CWE is a trademark of The MITRE Corporation. The MITRE Corporation hereby grants you a non-exclusive, royalty-free license to use CWE for research, development, and commercial purposes. Any copy you make for such purposes is authorized on the condition that you reproduce MITRE’s copyright designation and this license in any such copy. CWE Terms of Use

FAQ

QДля чего нужен CORS?
A

Браузеры применяют политику одного источника: JavaScript одного источника (сайта) не может свободно читать ответы другого сайта. CORS (Cross-Origin Resource Sharing) — это то, как сервер открывает исключение из этого правила, но только тем, кому явно разрешает. Заголовки ответа вроде Access-Control-Allow-Origin объявляют, каким источникам можно читать ответ.

QЧто открывает неправильная настройка CORS?
A

Слишком слабые разрешения могут позволить сайту злоумышленника читать через JavaScript ответы API пользователя с активным сеансом. Классические случаи: отражение Origin запроса обратно как разрешённого или установка Access-Control-Allow-Origin в * при одновременном разрешении учётных данных (кук). В результате персональные данные или токены могут попасть на сторонний сайт.

QЧто лежит в основе безопасной настройки?
A

Allowlist. Разрешайте только заранее определённые доверенные источники, а остальное запрещайте (запрет по умолчанию). Не отражайте Origin запроса вслепую. Для запросов с учётными данными не используйте * в Access-Control-Allow-Origin — указывайте конкретный источник. И открывайте кросс-доменно только те эндпоинты, которым это действительно нужно.

QУ меня ошибка CORS — поставить Access-Control-Allow-Origin в *?
A

Для API, которое возвращает только публичные данные без входа, * подходит. Но для запросов с учётными данными, например куками, браузер не даст странице прочитать ответ с *, так что ошибка останется. Если после этого перейти на отражение любого пришедшего Origin, ответ сможет прочитать любой сайт. Правильное решение — внести источник своего фронтенда в allowlist и возвращать его только при точном совпадении.

QПредотвращает ли настройка CORS атаки CSRF?
A

Нет. CORS управляет тем, можно ли прочитать ответ, а не тем, отправляется ли запрос. Простые запросы (например, POST в виде отправки формы) доходят до сервера даже без разрешения CORS. CSRF предотвращают CSRF-токенами и атрибутом кук SameSite.

QЧто такое preflight-запрос?
A

Прежде чем отправить настоящий запрос, браузер спрашивает сервер запросом OPTIONS, разрешены ли этот метод и эти заголовки. Так бывает при пользовательских заголовках, POST с application/json, PUT, DELETE и т. п. Если не разрешено, настоящий запрос не отправляется. Простые запросы — GET, HEAD или POST только с разрешёнными заголовками и типами содержимого — его не вызывают.