Как настроить CORS правильно: ошибки, примеры и best practices
CORS (Cross-Origin Resource Sharing) — это механизм безопасности браузера, который контролирует, какие сайты могут делать запросы к вашему API.
Важно сразу понять:
- CORS — это не защита сервера
- CORS — это ограничение браузера
Если CORS настроен неправильно:
- фронтенд «не работает» без видимой причины,
- появляются небезопасные конфигурации,
- разработчики ставят
*и молятся.
Разберём, как делать правильно.
Что такое origin
Origin — это комбинация:
scheme(http / https)hostport
Примеры:
https://example.com≠http://example.comhttps://example.com≠https://api.example.comhttps://example.com:3000≠https://example.com
Когда вообще нужен CORS
CORS применяется только если:
- запрос идёт из браузера
- origin отличается от origin API
❗ Сервер–сервер запросы (curl, backend, cron) CORS не затрагивает.
Simple request vs Preflight
Simple request
Запрос считается простым, если:
- методы:
GET,POST,HEAD - заголовки стандартные
Content-Type:text/plain,application/x-www-form-urlencoded,multipart/form-data
→ preflight не выполняется
Preflight (OPTIONS)
Происходит, если:
PUT,PATCH,DELETE- кастомные заголовки (
Authorization) application/json
Браузер сначала шлёт:
OPTIONS /api/resource
И ждёт корректные CORS-заголовки.
Основные CORS-заголовки
Access-Control-Allow-Origin
Access-Control-Allow-Origin: https://frontend.example.com❌ Ошибка:
Access-Control-Allow-Origin: *если используются cookies или auth.
Access-Control-Allow-Methods
Access-Control-Allow-Methods: GET, POST, PUT, DELETEAccess-Control-Allow-Headers
Access-Control-Allow-Headers: Content-Type, AuthorizationAccess-Control-Allow-Credentials
Access-Control-Allow-Credentials: true❗ Требует конкретный origin, * запрещён.
Пример корректной конфигурации (Nginx)
location /api/ {
add_header Access-Control-Allow-Origin https://frontend.example.com;
add_header Access-Control-Allow-Credentials true;
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS";
add_header Access-Control-Allow-Headers "Content-Type, Authorization";
if ($request_method = OPTIONS) {
return 204;
}
proxy_pass http://backend;
}Частые ошибки CORS
❌ Access-Control-Allow-Origin: * + cookies
Так не работает и никогда не будет.
❌ OPTIONS не обрабатывается
Результат:
CORS policy: Response to preflight request doesn't pass access control check
OPTIONS обязательно должен возвращать 2xx.
❌ CORS включён только на 200 ответы
Ошибка часто возникает при:
- 401
- 403
- 500
Решение:
- заголовки должны добавляться всегда, даже при ошибках.
❌ Доверие заголовку Origin без валидации
add_header Access-Control-Allow-Origin $http_origin;Опасно, если не фильтровать whitelist.
Best practices
✅ Явный whitelist origin’ов
https://app.example.com
https://admin.example.com
✅ Отдельная CORS-логика
- middleware
- ingress
- gateway
Не размазывать по бизнес-коду.
✅ Кэширование preflight
Access-Control-Max-Age: 3600Снижает количество OPTIONS-запросов.
✅ Разные CORS для prod / dev
Dev:
http://localhost:3000
Prod:
https://app.example.com
CORS ≠ Security
Важно:
- CORS не защищает API
- API должен проверять:
- авторизацию
- токены
- права доступа
Любой запрос можно сделать не из браузера.
Как дебажить CORS
- DevTools → Network → OPTIONS
- Смотреть:
- статус ответа
- заголовки
- Проверить:
- совпадает ли Origin
- разрешены ли headers/methods
Итоги
- CORS — это механизм браузера, а не сервера.
- Никогда не используйте
*с авторизацией. - OPTIONS должен всегда работать.
- Заголовки должны приходить даже при ошибках.
- Явный whitelist — лучший вариант.
Настроить мониторинг за 30 секунд
Надежные оповещения о даунтаймах. Без ложных срабатываний