Что такое CORS и как его правильно настроить

Представим ситуацию: мы разрабатываем современное веб-приложение, которое должно получать данные о погоде с внешнего API, загружать карты Google и интегрироваться с социальными сетями. Кажется, что ничего сложного — просто отправляем запросы на нужные адреса. Однако браузер категорически отказывается выполнять эти запросы, выбрасывая загадочную ошибку о CORS.
- Зачем нужен CORS
- Как работает механизм CORS
- Настройка CORS в разных окружениях
- Типичные ошибки и их решения
- Безопасность при использовании CORS
- Практические кейсы применения CORS
- Заключение
- Рекомендуем посмотреть курсы по веб разработке
Зачем нужен CORS
Cross-Origin Resource Sharing (CORS) — это механизм, который решает фундментальную проблему современной веб-разработки. Дело в том, что браузеры по умолчанию следуют политике «одного источника» (Same-Origin Policy), которая запрещает веб-страницам делать запросы к ресурсам, находящимся на других доменах, портах или протоколах. Эта политика была создана в целях безопасности — чтобы предотвратить ситуации, когда вредоносные скрипты могут получить доступ к конфиденциальным данным пользователя.
Однако современные приложения редко существуют в изоляции. Нам постоянно требуется обращаться к внешним сервисам: получать данные с API, загружать ресурсы с CDN, интегрироваться с платёжными системами. CORS предоставляет контролируемый способ обхода ограничений Same-Origin Policy, позволяя серверам явно указывать, какие домены могут получать доступ к их ресурсам.
Согласно нашим наблюдениям, понимание CORS становится критически важным навыком для любого фронтенд-разработчика. Без правильной настройки этого механизма невозможно создать полноценное современное веб-приложение, которое взаимодействует с внешним миром.
Как работает механизм CORS
Давайте разберёмся, как именно браузер принимает решение о том, разрешить или запретить кросс-доменный запрос. Весь процесс можно разбить на несколько ключевых этапов, каждый из которых играет важную роль в обеспечении безопасности.
Шаг 1: Отправка запроса с заголовком Origin
Когда наше приложение на домене https://frontend.example.com пытается обратиться к API на https://api.example.com, браузер автоматически добавляет к запросу специальный заголовок Origin: https://frontend.example.com. Этот заголовок информирует сервер о том, откуда именно пришёл запрос.

Диаграмма показывает путь запроса от клиента к серверу и обратно, где сервер с помощью заголовков сообщает браузеру, разрешён ли доступ. Это помогает быстро понять, кто принимает ключевые решения в процессе CORS.
Шаг 2: Анализ ответа сервера
Сервер, получив запрос, должен решить: разрешить ли доступ этому домену? Если да, то в ответе он включает заголовок Access-Control-Allow-Origin, указывающий разрешённые домены. Например: Access-Control-Allow-Origin: https://frontend.example.com или Access-Control-Allow-Origin: * для разрешения всем доменам.
Шаг 3: Финальное решение браузера
Браузер сравнивает значение Origin с полученным Access-Control-Allow-Origin. Если они совпадают (или сервер разрешил доступ всем доменам через *), запрос выполняется успешно. В противном случае браузер блокирует получение данных и выбрасывает знакомую многим ошибку CORS.
Ключевые заголовки CORS
Механизм CORS оперирует несколькими важными HTTP-заголовками:
- Access-Control-Allow-Methods — перечисляет HTTP-методы (GET, POST, PUT, DELETE), которые разрешены для кросс-доменных запросов.
- Access-Control-Allow-Headers — указывает, какие заголовки клиент может включать в запрос помимо стандартных.
Конечно, вот фрагмент, который можно скопировать и вставить прямо в статью для исправления неточности.
Важное уточнение: как правильно указывать разрешённые домены
При настройке заголовка Access-Control-Allow-Origin разработчики часто допускают одну и ту же ошибку, полагая, что он может принимать несколько значений. Давайте разберёмся, как это работает на самом деле.
Распространённое заблуждение: список доменов
Может показаться логичным, что для разрешения доступа нескольким сайтам можно просто перечислить их через запятую, например:
# ЭТО НЕПРАВИЛЬНО И НЕ БУДЕТ РАБОТАТЬ!
Access-Control-Allow-Origin: https://frontend.example.com, https://app.example.com
Это неверно. Спецификация CORS не позволяет передавать в заголовке Access-Control-Allow-Origin список доменов. Браузер ожидает увидеть только одно значение: либо конкретный домен, либо *. Если он получит список, он проигнорирует заголовок и заблокирует запрос.
Правильное решение: динамическая проверка на сервере
Чтобы предоставить доступ нескольким доменам, сервер должен быть настроен на динамическую обработку запросов. Вот как выглядит правильный алгоритм:
- Получение Origin: Сервер принимает запрос от клиента и считывает значение заголовка Origin. В этом заголовке указан домен, с которого пришёл запрос.
- Проверка по «белому списку»: Сервер сравнивает полученный Origin с заранее определённым списком разрешённых доменов (так называемым «белым списком»).
- Динамический ответ: Если Origin запроса находится в этом списке, сервер копирует его значение и вставляет в заголовок ответа Access-Control-Allow-Origin.
Таким образом, для каждого разрешённого запроса ответ будет уникальным, но всегда валидным:
- Запрос с Origin: https://frontend.example.com получит ответ Access-Control-Allow-Origin: https://frontend.example.com.
- Запрос с Origin: https://app.example.com получит ответ Access-Control-Allow-Origin: https://app.example.com.
- Запрос с Origin: https://malicious-site.com не найдёт совпадения в списке, и сервер либо вообще не вернёт этот заголовок, либо вернёт домен по умолчанию, что приведёт к блокировке запроса браузером.
Этот подход обеспечивает безопасность и соответствует стандартам CORS.
Особый случай: preflight-запросы
Не все запросы выполняются напрямую. Если мы отправляем «сложный» запрос (например, POST с нестандартными заголовками или PUT-запрос), браузер сначала делает предварительный OPTIONS-запрос к серверу — так называемый preflight. Этот запрос проверяет, разрешён ли основной запрос, и только после получения положительного ответа выполняет реальный запрос с данными. Понимание этого механизма критически важно для правильной настройки сервера.
Настройка CORS в разных окружениях
Теория — это хорошо, но как применить знания на практике? Рассмотрим конкретные способы настройки CORS в популярных серверных и клиентских окружениях, с которыми мы регулярно сталкиваемся в реальных проектах.
Настройка CORS на сервере
Node.js с Express: простой подход
Самый быстрый способ включить CORS в Express-приложении — использовать готовую библиотеку cors. Установим её и настроим базовую конфигурацию:
const express = require('express'); const cors = require('cors'); const app = express(); // Разрешаем CORS для всех доменов (подходит для разработки) app.use(cors()); // Или более безопасный вариант для продакшена app.use(cors({ origin: ['https://frontend.example.com', 'https://app.example.com'], methods: ['GET', 'POST', 'PUT', 'DELETE'], allowedHeaders: ['Content-Type', 'Authorization'] })); app.listen(3000, () => console.log('Server running on port 3000'));
Ручная настройка в Node.js
Если мы предпочитаем больший контроль или не хотим подключать дополнительные зависимости, можем настроить CORS самостоятельно:
app.use((req, res, next) => { res.header('Access-Control-Allow-Origin', 'https://frontend.example.com'); res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS'); res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization'); // Обработка preflight-запросов if (req.method === 'OPTIONS') { res.sendStatus(200); } else { next(); } });
Python с Flask
В экосистеме Python процесс ещё проще благодаря библиотеке flask-cors:
from flask import Flask from flask_cors import CORS app = Flask(__name__) CORS(app) # Включаем CORS для всех маршрутов # Или с детальной настройкой CORS(app, origins=['https://frontend.example.com'], methods=['GET', 'POST'], allow_headers=['Content-Type', 'Authorization']) if __name__ == '__main__': app.run()
Важная деталь: при настройке origin в продакшене всегда указывайте конкретные домены вместо символа *. Это существенно повышает безопасность приложения и защищает от потенциальных атак.
Настройка CORS на клиенте
Иногда проблема CORS возникает только в процессе разработки, когда наш фронтенд работает на localhost:4200, а API — на localhost:3000. В продакшене эти сервисы могут находиться на одном домене, но для локальной разработки нужно решение.
Angular: настройка прокси
В Angular мы можем создать файл proxy.conf.json в корне проекта:
{ "/api/*": { "target": "http://localhost:3000", "secure": false, "changeOrigin": true, "logLevel": "debug" } }
Затем запускаем dev-сервер с использованием прокси:
ng serve --proxy-config proxy.conf.json
Теперь все запросы к /api/* будут автоматически перенаправляться на наш бэкенд, обходя ограничения CORS. Браузер будет думать, что запросы идут на тот же домен, что и фронтенд-приложение.
Этот подход особенно удобен для команд, где фронтенд и бэкенд разрабатываются параллельно разными специалистами.
Типичные ошибки и их решения
В работе с CORS мы регулярно сталкиваемся с одними и теми же проблемами. Давайте разберём самые частые ошибки и эффективные способы их устранения — это сэкономит нам много времени на отладке.
No ‘Access-Control-Allow-Origin’ header is present on the requested resource
Классическая ошибка, с которой знаком каждый фронтенд-разработчик. Возникает, когда сервер не отправляет нужный заголовок CORS.
Решение: Убедитесь, что на сервере настроена отправка заголовка Access-Control-Allow-Origin. Проверьте, что middleware или обработчик CORS применяется ко всем нужным маршрутам.
// Неправильно: middleware добавлен после маршрутов app.get('/api/data', (req, res) => res.json({data: 'test'})); app.use(cors()); // Правильно: middleware добавлен до маршрутов app.use(cors()); app.get('/api/data', (req, res) => res.json({data: 'test'}));
Preflight OPTIONS request fails
Браузер отправляет предварительный OPTIONS-запрос, но сервер не умеет его обрабатывать или возвращает ошибку.
Решение: Добавьте обработку OPTIONS-запросов на сервере:
app.use((req, res, next) => { if (req.method === 'OPTIONS') { res.header('Access-Control-Allow-Origin', '*'); res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE'); res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization'); return res.sendStatus(200); } next(); });
CORS error with cookies or authentication
При работе с cookies или токенами аутентификации стандартная настройка CORS может не сработать.
Решение: Для передачи cookies нужна дополнительная настройка:
// На сервере app.use(cors({ origin: 'https://frontend.example.com', // Не может быть '*' при credentials: true credentials: true })); // На клиенте (fetch) fetch('https://api.example.com/data', { credentials: 'include' });
Wildcard ‘*’ not allowed when credentials are enabled
Попытка использовать Access-Control-Allow-Origin: * вместе с credentials: true.
Решение: При включении credentials необходимо явно указать допустимые домены:
// Неправильно res.header('Access-Control-Allow-Origin', '*'); res.header('Access-Control-Allow-Credentials', 'true'); // Правильно res.header('Access-Control-Allow-Origin', 'https://frontend.example.com'); res.header('Access-Control-Allow-Credentials', 'true');
Custom headers blocked
Браузер блокирует запросы с нестандартными заголовками (например, X-API-Key).
Решение: Добавьте нужные заголовки в Access-Control-Allow-Headers:
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, X-API-Key, X-Requested-With');
Наш опыт показывает, что большинство проблем с CORS решается правильной настройкой этих базовых аспектов. Главное — помнить о последовательности обработки middleware и особенностях работы с cookies.

Столбчатая диаграмма демонстрирует условную частоту наиболее распространённых ошибок при работе с CORS. Такой обзор помогает сразу понять, какие проблемы встречаются чаще всего и требуют особого внимания.
Безопасность при использовании CORS
CORS представляет собой компромисс между функциональностью и безопасностью. С одной стороны, он позволяет создавать гибкие современные приложения, с другой — неправильная настройка может открыть серьёзные уязвимости. Давайте разберёмся, как найти правильный баланс.
Опасность использования wildcard (*)
Самая распространённая ошибка — установка Access-Control-Allow-Origin: * в продакшене. Кажется, что это решает все проблемы одним махом, но на самом деле открывает наши API для любого сайта в интернете. Представьте: злоумышленник может создать вредоносную страницу, которая будет делать запросы к нашему API от имени ничего не подозревающих пользователей.
Принцип наименьших привилегий
Правильный подход — явно указывать только те домены, которым действительно нужен доступ:
// Небезопасно для продакшена app.use(cors({ origin: '*' })); // Безопасная настройка app.use(cors({ origin: ['https://app.example.com', 'https://admin.example.com'], methods: ['GET', 'POST'], // Только необходимые методы allowedHeaders: ['Content-Type', 'Authorization'] // Только нужные заголовки }));
Влияние на защиту от CSRF и XSS
CORS не является панацеей от всех атак. Неправильная настройка может усугубить уязвимости к межсайтовой подделке запросов (CSRF) и межсайтовому скриптингу (XSS). Если мы разрешаем доступ слишком широкому кругу доменов, злоумышленник может использовать это для проведения атак с других сайтов.
Исследования показывают, что сочетание правильно настроенного CORS с дополнительными мерами безопасности (CSRF-токены, Content Security Policy, HTTPS) обеспечивает надёжную защиту современных веб-приложений.
Баланс между удобством и безопасностью
В процессе разработки мы часто сталкиваемся с искушением упростить настройки CORS ради скорости. Однако стоит помнить: то, что работает в dev-окружении, не всегда подходит для продакшена. Рекомендуем использовать переменные окружения для различных конфигураций и никогда не деплоить приложение с wildcard-настройками в production.
Практические кейсы применения CORS
Теория становится понятнее, когда мы видим реальные примеры использования. Рассмотрим несколько типичных сценариев, где CORS играет ключевую роль в функционировании современных веб-приложений.
Работа с изображениями и файлами с CDN
Часто мы размещаем статические ресурсы на отдельном домене или CDN для оптимизации производительности. Например, наше приложение находится на app.example.com, а изображения — на cdn.example.com. Для обработки изображений через Canvas API браузеру нужно разрешение CORS:
// Без правильной настройки CORS этот код вызовет ошибку const img = new Image(); img.crossOrigin = 'anonymous'; img.src = 'https://cdn.example.com/photo.jpg'; img.onload = () => { const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d'); ctx.drawImage(img, 0, 0); };
Интеграция с публичными API
Современные приложения активно используют внешние сервисы. Интеграция с картами Google, API социальных сетей, сервисами погоды — все эти задачи требуют корректной настройки CORS со стороны поставщика API. Например, для работы с API GitHub нам не нужно беспокоиться о настройке CORS — GitHub уже настроил свои серверы для поддержки кросс-доменных запросов.
Микросервисная архитектура
В современных корпоративных приложениях различные части системы часто развёрнуты на разных поддоменах: auth.company.com для аутентификации, api.company.com для бизнес-логики, files.company.com для файлового хранилища. CORS здесь обеспечивает безопасное взаимодействие между компонентами системы, позволяя фронтенду на app.company.com обращаться ко всем необходимым сервисам.

Схема показывает, как фронтенд-приложение взаимодействует с несколькими сервисами (API, аутентификация, файловое хранилище) в разных доменах. Здесь CORS обеспечивает безопасный обмен данными между компонентами системы.
Возникает вопрос: можно ли обойтись без CORS в таких сценариях? Технически да — можно проксировать все запросы через основной сервер приложения. Однако это добавляет ненужную нагрузку и усложняет архитектуру. CORS предоставляет элегантное решение, позволяя компонентам взаимодействовать напрямую при соблюдении требований безопасности.
Заключение
Cross-Origin Resource Sharing — это не просто техническая деталь, а фундаментальный механизм, который делает возможным существование современного интернета в том виде, в каком мы его знаем. Мы рассмотрели, как CORS решает противоречие между безопасностью браузера и потребностями разработчиков в создании интегрированных приложений.
- CORS решает проблему политики одного источника. Он позволяет безопасно обращаться к ресурсам на других доменах.
- Механизм работает через заголовки HTTP. Сервер указывает, кому разрешён доступ, а браузер принимает окончательное решение.
- Preflight-запросы проверяют допустимость сложных операций. Это помогает избежать небезопасных действий.
- Настройка CORS зависит от окружения. Для Node.js, Flask и Angular существуют готовые решения.
- Ошибки CORS встречаются часто. Их можно устранить корректной настройкой заголовков и middleware.
- Безопасность — главный приоритет. Использование * в продакшене недопустимо.
- Практические кейсы показывают важность CORS. Он необходим для работы API, CDN и микросервисов.
Если вы только начинаете осваивать профессию фронтенд-разработчика, рекомендуем обратить внимание на подборку курсов по веб-разработке. В них есть как теоретическая часть для понимания базовых принципов, так и практические задания для закрепления навыков.
Рекомендуем посмотреть курсы по веб разработке
Курс | Школа | Цена | Рассрочка | Длительность | Дата начала | Ссылка на курс |
---|---|---|---|---|---|---|
Веб-разработчик
|
Eduson Academy
71 отзыв
|
Цена
Ещё -5% по промокоду
119 000 ₽
|
От
9 917 ₽/мес
|
Длительность
12 месяцев
|
Старт
6 октября
|
Ссылка на курс |
Профессия: ВЕБ-разработчик
|
ProductStar
38 отзывов
|
Цена
Ещё -16% по промокоду
129 600 ₽
288 000 ₽
|
От
5 520 ₽/мес
Рассрочка на 2 года.
11 600 ₽/мес
|
Длительность
10 месяцев
|
Старт
18 сентября
|
Ссылка на курс |
Веб-разработчик с нуля
|
Нетология
43 отзыва
|
Цена
с промокодом kursy-online
150 708 ₽
264 400 ₽
|
От
4 186 ₽/мес
Без переплат на 2 года.
7 222 ₽/мес
|
Длительность
17 месяцев
|
Старт
5 октября
|
Ссылка на курс |
Веб-разработчик: код фрилансера
|
WayUP
19 отзывов
|
Цена
35 940 ₽
39 940 ₽
|
От
3 994 ₽/мес
Есть рассрочка.
|
Длительность
3 месяца
|
Старт
23 сентября
|
Ссылка на курс |

Оборудование фотографа: что купить, а без чего можно обойтись?
Выбор фототехники — тот еще квест. Зеркалка или беззеркалка? Какой объектив нужен в первую очередь? И правда ли, что хороший штатив — залог успеха? Разбираемся!

Конкурентный анализ в бизнесе: методы, цели и ошибки
Конкурентный анализ — это не про слежку, а про здравый смысл. Как он помогает находить слабые места в нише, повышать прибыль и не повторять чужие ошибки? В статье — примеры и советы.

Как технологии меняют подбор персонала: лучшие HR-инструменты
AI, автоматический скрининг, интеграции с CRM — подбор персонала становится все технологичнее. Какие инструменты реально работают, а какие — просто красивые обещания?

Как поставить знак «не равно» в Excel и Word
Если вы не понимаете, как поставить знак не равно в Excel или почему он не работает в формулах — эта статья для вас. Будет и понятно, и с юмором.