Кросс-доменные запросы давно перестали быть загадкой для веба, но ошибка в конфигурации может дорого обойтись. В этой статье разберём, как грамотно выполнить CORS настройка и безопасность, чтобы открывать доступ там, где это нужно, и закрывать — где нельзя.
Что такое CORS и зачем его настраивать
Cross-Origin Resource Sharing — это механизм браузера, который регулирует доступ одной страницы к ресурсам, расположенным на другом домене. Политика введена ради безопасности: без неё любой сайт мог бы бесконтрольно обращаться к API и читать ответы.
Настройка нужна, чтобы разрешать легитимный обмен между фронтендом и бэкендом, одновременно ограничивая потенциально опасные сценарии. Корректно настроенный CORS — часть общей стратегии защиты веб-приложения, наряду с аутентификацией и ограничением прав.
Как работает механизм CORS — простая модель
Браузер добавляет заголовок Origin в запрос, который показывает источник (схема, домен, порт). Сервер смотрит этот заголовок и решает, возвращать ли ответ вместе с Access-Control-Allow-Origin, указывающим разрешённый источник.
Для некоторых операций — нестандартных методов или нестандартных заголовков — браузер сначала отправляет preflight-запрос OPTIONS. Сервер в ответ должен вернуть набор разрешений, иначе основной запрос будет блокирован. Это простая и безопасная модель, если на стороне сервера выполняется внятная логика валидации происхождения запросов.
Типичные ошибки и реальные риски
Самая частая ошибка — установка Access-Control-Allow-Origin: * в API, которые принимают учётные данные или возвращают чувствительные данные. Такой универсальный доступ годится для статических ресурсов, но опасен при работе с cookie или токенами.
Другой распространённый промах — включение Allow-Credentials вместе с wildcard-оригином. Браузер отклонит такой ответ, но нередко это сопровождается попытками «обойти» политику на клиенте, что ведёт к уязвимостям. Также разработчики иногда разрешают слишком широкий набор методов и заголовков, что расширяет поверхность атаки.
Наконец, забывают про Vary: Origin. Без этой подсказки прокси и CDN могут кэшировать ответ с одним Origin и отдать его другому, что нарушит изоляцию. В сумме эти ошибки увеличивают риск кражи данных, подлогов запросов и обхода аутентификации.
Принципы безопасной конфигурации
Безопасность — это набор ограничений, а не их отсутствие. Лучше разрешать доступ по списку доверенных источников, чем открывать доступ всем подряд.
Ниже — практические правила, которые применимы к большинству сервисов:
- Указывайте конкретные Origin вместо звёздочки, когда работа идёт с credentials (cookie, Authorization). Это снижает шанс непреднамеренного раскрытия.
- Используйте Access-Control-Allow-Credentials только при реальной необходимости. Токены лучше передавать в заголовках Authorization, а cookie — с правильными флагами SameSite и Secure.
- Ограничивайте список разрешённых методов (GET, POST, PATCH и т. п.), не давайте лишних OPTIONS, PUT, DELETE без причины.
- Контролируйте заголовки через Access-Control-Allow-Headers и не позволяйте клиентам самоназначать произвольные заголовки, если это не требуется.
- Добавляйте Vary: Origin, чтобы кэширующие промежуточные звенья корректно обрабатывали разные Origin.
- Внедрите rate limiting и WAF для защиты от злоупотреблений, даже если CORS настроен правильно.
Примеры настройки на популярных платформах
Практика показывает, что настройки зависят от стека. В простых случаях достаточно middleware, в сложных — гибкой логики и валидации Origin по базе доверенных доменов.
Ниже таблица с ключевыми моментами для Express, nginx и Apache — краткая шпаргалка по заголовкам и рекомендациям.
| Платформа | Ключевой заголовок | Рекомендация |
|---|---|---|
| Express (Node.js) | Access-Control-Allow-Origin, Access-Control-Allow-Credentials | Использовать middleware, проверяющее Origin по списку; не ставить ‘*’ при credentials |
| nginx | add_header Access-Control-Allow-Origin; | Динамически подставлять Origin в ответ через переменные и проверку в конфиге; не кэшировать без Vary |
| Apache | Header set Access-Control-Allow-Origin | Использовать директивы или модуль, чтобы фильтровать Origin; избегать blanket-правил |
Небольшой пример логики на сервере: проверять Origin, сопоставлять с белым списком и только при совпадении добавлять соответствующий заголовок. Такой подход гарантирует, что другие домены не увидят разрешённого ответа.
Короткая иллюстрация: Express
В Express удобнее всего написать middleware, который берёт Origin из запроса и сверяет его со списком доверенных. Если совпадает, в ответ добавляется конкретный Origin и, при необходимости, Allow-Credentials.
Это даёт гибкость: можно хранить белый список в БД или конфигурации окружения и обновлять его без перезапуска сервера. Такой способ часто использовал в проектах с несколькими фронтендами и мобильными приложениями.
Отладка, тестирование и типичные ловушки
При тестировании важно проверять как простые GET-запросы, так и preflight. Инструменты разработчика в браузере покажут, какие заголовки были отправлены и какие возвращены, а также причину блокировки.
Частая ловушка — корректное поведение в локальной среде и неправильное в продакшене из-за прокси, CDN или балансировщика. Убедитесь, что заголовки не перезаписываются и не кэшируются посредниками. Я лично сталкивался с багом, где nginx подставлял универсальный Origin в ответ, что сломало изоляцию между клиентами.
Как CORS вписывается в общую модель безопасности
CORS — не единственный барьер, он дополняет аутентификацию, авторизацию и защиту от CSRF. Полагаться только на CORS — плохая идея, потому что при уязвимом API злоумышленник может получить данные и без браузера, напрямую обращаясь к сервису.
Поэтому всегда комбинируйте: проверяйте права доступа на сервере, храните токены в безопасных местах, применяйте политики CSP и корректные флаги у cookie. CORS должен ограничивать браузерное взаимодействие, а сервер — контролировать доступ в принципе.
Рекомендации для разработки и деплоя
В среде разработки можно временно ослабить ограничения ради скорости работы, но обязательно документировать эти исключения и не переносить их в продакшен. Используйте переменные окружения для управления белыми списками и признаками debug.
На этапе деплоя проверьте конфигурацию через автоматические тесты: имитация запросов с разных Origin, проверка preflight и корректности заголовков Vary и Cache-Control. Это помогает избежать сюрпризов, когда приложение попадает за CDN или прокси.
Небольшой практический совет по мониторингу: логируйте Origin в ошибочных запросах и настраивайте алерты на всплески подозрительной активности. Это часто даёт первые сигналы о попытках автоматизированного сканирования или эксплуатации уязвимости.
Правильная настройка кросс-доменных запросов — не про одно заглавие в конфиге, а про систему ограничений, тестов и наблюдаемости. Начиная с чёткого белого списка и заканчивая мониторингом аномалий, вы снижаете риски и сохраняете удобство интеграции между сервисами.

