CORS
Что такое CORS и зачем он нужен
CORS (Cross-Origin Resource Sharing) — это механизм безопасности браузера, который контролирует, может ли страница с одного источника (схема+домен+порт) обращаться к ресурсам другого источника. По умолчанию браузер ограничивает доступ из скриптов к ответам с другого источника. CORS позволяет серверу явно указать, кому и что можно запрашивать, с помощью специальных заголовков.
Origin — комбинация схемы (http/https), домена и порта. Разные порты уже разные источники.
Браузер автоматически применяет правила CORS; для запросов с бекенда (сервер->сервер) CORS не требуется.
Сервер решает, какие источники допустить, какими методами и с какими заголовками.
Типы запросов и preflight (предварительный) запрос
Браузер различает простые запросы и запросы, требующие предварительной проверки (preflight). Preflight посылается методом OPTIONS
и спрашивает у сервера разрешение на основной запрос.
Простые запросы: методы GET/HEAD/POST, заголовки только из безопасного набора (например,
Accept
,Content-Type: application/x-www-form-urlencoded | text/plain | multipart/form-data
), без нестандартных заголовков.Не простые: любые другие методы (PUT, PATCH, DELETE), кастомные заголовки (например,
X-Request-Id
),Content-Type
c application/json — всё это требует preflight.
Ключевые CORS-заголовки и их смысл
Access-Control-Allow-Origin
— кому разрешено. Значение: конкретный origin (например,https://app.example.com
) или*
(всем).Access-Control-Allow-Methods
— какие методы разрешены (GET, POST, PUT, DELETE, ...).Access-Control-Allow-Headers
— какие запросные заголовки разрешены (например,Content-Type, Authorization
).Access-Control-Allow-Credentials
— можно ли отправлять куки/HTTP-авторизацию (true
/false
).Access-Control-Expose-Headers
— какие заголовки ответа будут доступны JS (по умолчанию доступ к большинству заголовков закрыт).Access-Control-Max-Age
— сколько секунд кешировать результат preflight, чтобы реже делатьOPTIONS
.Vary: Origin
— сообщает кешам, что ответ зависит от заголовкаOrigin
.
Быстрый старт: пакет cors
Проще всего управлять CORS через официальный пакет cors
для Express.
Whitelist и динамический origin
Credentials (куки, заголовки авторизации) безопасно
Чтобы браузер отправлял и принимал куки/токены между источниками, нужны настройки и на клиенте, и на сервере.
Сервер:
credentials: true
иAccess-Control-Allow-Origin
не может быть*
.Клиент: для fetch/axios указывается
credentials: "include"
.Куки: настройте
SameSite=None; Secure
(иначе межсайтовая передача будет заблокирована современными браузерами).Только HTTPS для
SameSite=None; Secure
.
Ручная настройка без пакета cors (понимание механики)
Иногда полезно явно увидеть ответы на preflight и основной запрос.
Оптимизация preflight (производительность)
Используйте
Access-Control-Max-Age
для кеширования разрешения браузером (например, 600–3600 секунд).Сведите к минимуму нестандартные заголовки и меняйте их только при необходимости — меньше причин для preflight.
Стабилизируйте набор методов и заголовков — частые изменения могут приводить к лишним
OPTIONS
.
Безопасность: частые ошибки и как их избежать
Отражение Origin без валидации: установка
Access-Control-Allow-Origin
равным входящемуOrigin
без whitelist — риск утечки данных. Всегда проверяйте против списка.Allow-Credentials с *: браузер заблокирует такой ответ; используйте конкретный origin.
Слишком широкий Allow-Headers: разрешайте только нужные заголовки, чтобы сузить поверхность атаки.
Отсутствует Vary: Origin: кэши могут отдать ответ не тому источнику. Добавляйте
Vary
при динамическом разрешении origin.HTTP вместо HTTPS: для
SameSite=None
куки должны бытьSecure
, то есть только HTTPS.
Отладка и диагностика
Смотрите вкладку "Network" в DevTools: есть ли запрос
OPTIONS
, какие заголовки пришли/ушли.Проверьте консоль: браузер пишет причину блокировки CORS (какого заголовка не хватает).
Логируйте на сервере заголовки
Origin
,Access-Control-Request-Method
,Access-Control-Request-Headers
для preflight.Тестируйте curl-ом серверную реакцию (curl не применяет CORS, но помогает увидеть заголовки ответа).
Dev proxy как альтернатива при локальной разработке
Чтобы реже трогать CORS в деве, используйте прокси в дев-сервере фронта (Vite/webpack). Тогда запросы уходят на тот же origin, а прокси перенаправляет их на API.
Краткий чек-лист настроек
Определите, какие фронтенды (origin) должны иметь доступ — сделайте whitelist.
Разрешите только нужные методы и заголовки (
Allow-Methods
,Allow-Headers
).Если нужны куки/авторизация —
credentials: true
, конкретныйAllow-Origin
, куки сSameSite=None; Secure
.Настройте
Max-Age
для кеширования preflight.Добавьте
Vary: Origin
при динамическом разрешении.