Как настроить CORS правильно: ошибки, примеры и best practices

6 минут чтения
Средний рейтинг статьи — 4.8

CORS (Cross-Origin Resource Sharing) — это механизм безопасности браузера, который контролирует, какие сайты могут делать запросы к вашему API.

Важно сразу понять:

  • CORS — это не защита сервера
  • CORS — это ограничение браузера

Если CORS настроен неправильно:

  • фронтенд «не работает» без видимой причины,
  • появляются небезопасные конфигурации,
  • разработчики ставят * и молятся.

Разберём, как делать правильно.

Что такое origin

Origin — это комбинация:

  • scheme (http / https)
  • host
  • port

Примеры:

  • https://example.comhttp://example.com
  • https://example.comhttps://api.example.com
  • https://example.com:3000https://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, DELETE

Access-Control-Allow-Headers

Access-Control-Allow-Headers: Content-Type, Authorization

Access-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

  1. DevTools → Network → OPTIONS
  2. Смотреть:
    • статус ответа
    • заголовки
  3. Проверить:
    • совпадает ли Origin
    • разрешены ли headers/methods

Итоги

  • CORS — это механизм браузера, а не сервера.
  • Никогда не используйте * с авторизацией.
  • OPTIONS должен всегда работать.
  • Заголовки должны приходить даже при ошибках.
  • Явный whitelist — лучший вариант.
6 минут чтения
Средний рейтинг статьи — 4.8

Настроить мониторинг за 30 секунд

Надежные оповещения о даунтаймах. Без ложных срабатываний