javascript

CORS для собеседований и работы

  • воскресенье, 10 августа 2025 г. в 00:00:06
https://habr.com/ru/articles/935636/

Если вы видите эту ошибку — вы не одиноки:

Access to fetch at 'https://api.site.com' from origin 'http://localhost:3000' 
has been blocked by CORS policy.

Разберем, почему это происходит, и как это починить. Что такое CORS, и для чего он нужен.

1.     Зачем нужен CORS? Безопасность! 

Пример атаки:

  1. Вы вошли на bank.com. Данные для авторизации сохранились в куках.

  2. Заходите на evil.com.

  3. Сайт evil.com тайно отправляет запрос Get /api/account на bank.com.

  4. Браузер автоматически отправляет куки к запросу на bank.com → злоумышленник получает данные счета и, возможно, списывает деньги.

2.     Что такое CORS?

CORS (Cross-Origin Resource Sharing) - русского обозначения не имеет. Дословно "межисточниковый" обмен ресурсами.

  • Цель браузера: защитить пользователя от вредоносных сайтов за счет блокировки запросов к неразрешенным ресурсам.

  • Как работает:

    • Браузер выполняет вызов ресурса.

    • Получает заголовки Access-Control.

    • Проверяет разрешенные заголовки на соответствие домена и запроса.

    • Блокирует или разрешает чтение результата запроса.

Пример: пользователь открывает сайт evil.com. Если bank.com настроил CORS, JavaScript на evil.com не сможет прочитать ответ от bank.com/api/account.

CORS не защищает от кросс-доменных запросов (CSRF-атак). Браузер проверяет заголовки после получения ответа, блокируя передачу ответа в js код.

3. Заголовки CORS

# Разрешённые домены (один, список или *)
Access-Control-Allow-Origin: https://frontend.com 

# Разрешённые HTTP-методы (список или *)
Access-Control-Allow-Methods: POST, GET, OPTIONS, DELETE

# Разрешённые заголовки для отправки(предварительный запрос)
Access-Control-Allow-Headers: Authorization, Content-Type, X-Requested-With

# Разрешённые для чтения заголовки (основной запрос)
Access-Control-Expose-Headers: Authorization, Content-Type, X-Requested-With

# Разрешить передачу кук/токенов
Access-Control-Allow-Credentials: true

# Кэшировать предварительный запрос на 600 сек (10 мин)
Access-Control-Max-Age: 600

4. Предзапросы (Preflight-запросы)

"Простые запросы" (GET, POST, HEAD без спец. заголовков) отправляются сразу.

"Сложные запросы", например, с методами PUT, DELETE или с нестандартными заголовками, сначала отправляют "предзапрос" (preflight request) методом OPTIONS.

Сервер должен ответить, разрешены ли такие запросы.

Например, перед вызовом GET с заголовком X-API-Key будет выполнен запрос:

http

/data HTTP/1.1 
Origin: https://frontend.com
Access-Control-Request-Headers: X-API-Key 

Сервер должен ответить:

http

HTTP/1.1 204 OK 
Access-Control-Allow-Origin: https://frontend.com 
Access-Control-Allow-Headers: X-API-Key 

И только потом отправится основной запрос. 

5. Что считается "разными источниками"?

При настройке CORS браузеры блокируют запросы руководствуясь "Политикой одинакового источника" или Same-Origin Policy (SOP).

Источник определяется тремя параметрами:

  1. Протокол (http/https)

  2. Домен (site.com/api.site.com)

  3. Порт (:80/:3000)

✅ Одинаковые источники:

https://site.com/page и https://site.com/about (отличаются путем или аргументами)


❌ Разные источники:

http://site.com и https://site.com (разный протокол)

https://site.com и https://api.site.com (разный домен)

6. Как работает CORS на практике? 

1. Простые запросы (GET/POST без спец. заголовков)

Браузер разрешает их, но не даст прочитать ответ, если сервер не добавит в ответ:

http

Access-Control-Allow-Origin: https://your-frontend.com

2. Сложные запросы (PUT, DELETE, кастомные заголовки)

Браузер сначала отправляет предзапрос (OPTIONS). Сервер должен ответить:

http

Access-Control-Allow-Origin: https://your-frontend.com
Access-Control-Allow-Methods: POST, DELETE
Access-Control-Allow-Headers: Content-Type

→ Затем браузер отправит основной запрос.

7. Пример для Express.js:

// Разрешить запросы с frontend.com
app.use((req, res, next) => {
  res.setHeader('Access-Control-Allow-Origin', 'https://frontend.com');
  res.setHeader('Access-Control-Allow-Methods', 'GET, POST');
  res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
  next();
});

8. Лучшие практики CORS

1.Не используйте * для защищенных данных

Разрешайте только доверенные домены:

Access-Control-Allow-Origin: https://your-frontend.com

2.Для публичных API можно использовать *:

Access-Control-Allow-Origin: *

3.Куки = осторожно!

Если используете куки:

http

Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: https://frontend.com // Нельзя использовать *

4.Тестируйте предзапросы:

Для PUT, DELETE и запросов с Authorization всегда настраивайте обработку OPTIONS.

  • Используйте Access-Control-Max-Age чтобы снизить нагрузку

  • Настройте веб-сервер (Nginx/Apache) для оптимизации, обработки OPTIONS без запуска приложения 

9. Частые ошибки

1.     Забыли добавить заголовки на сервере → Браузер блокирует ответ.

2.     Использовали * с куками → CORS ошибка.

3.     Не настроили OPTIONS для сложных запросов → Предзапрос проваливается.

10. Итог:

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

💡 Проверка: Откройте вкладку Network в DevTools. Ищите статусы OPTIONS и CORS headers в ответах сервера.

11. Что почитать:

W3C Cross-Origin Resource Sharing
Оригинальная спецификация CORS (2014) https://www.w3.org/TR/cors/

MDN Web Docs: Cross-Origin Resource Sharing (CORS)
https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS

Браузерная безопасность (Same-Origin Policy)
Подробное объяснение политики одинакового источника
https://web.dev/articles/same-origin-policy

CORS для разработчиков (Google Web Fundamentals)
Практические сценарии настройки с примерами кода
https://web.dev/articles/cross-origin-resource-sharing

Готовлю на мидл+/сеньора. Собираю материал для подготовки к собеседованию и делаю простым для понимания. Хочу сделать цикл статей, если у вас есть темы трудные для понимания - пишите, по возможности помогу.