На чьей стороне проверяется CORS — на фронтенде или бэкенде?
Что проверяют
Понимаете ли вы, кто именно кого ограничивает. Формулировка «на фронте или на бэке» провокационная: правильный ответ разделяет того, кто объявляет правило, и того, кто его применяет.
Как отвечать
Правило объявляет сервер заголовками, а применяет браузер. Бэкенд отдаёт Access-Control-Allow-Origin и соседние заголовки, но блокирует ответ именно браузер, исполняя политику одного источника. Никакой проверки на фронтенде в коде нет: скрипт не может ни включить, ни выключить CORS.
Отсюда следствия, которые стоит назвать:
- для простого запроса сервер его уже получил и выполнил, браузер лишь прячет ответ от скрипта. Побочный эффект при этом случился;
- непростой запрос (свой заголовок, метод
PUTилиDELETE, тело вapplication/json) предваряется запросомOPTIONS, и отвечать на него должен сервер, перечисляя разрешённые методы и заголовки; curlи клиенты для отладки политику не исполняют, поэтому «в консоли работает, а из браузера нет» это не баг сервера;- вместе с
Access-Control-Allow-Credentialsзвёздочка в источнике запрещена: нужен точный список иVary: Origin, иначе кэш отдаст чужой ответ.
В Python это настраивается посредником: CORSMiddleware в FastAPI, django-cors-headers, flask-cors. Формулировка для финала: CORS ослабляет политику одного источника контролируемым образом, а не добавляет защиту.
Где спотыкаются
Говорят, что CORS защищает от CSRF. Скорее наоборот: браузер мешает прочитать ответ, но отправку запроса не запрещает, и от подделки запроса спасают токен и SameSite. Отражение любого источника вместе с разрешёнными учётными данными как раз открывает чужому сайту доступ к API от имени пользователя.
Второе: чинят CORS на клиенте, дописывая заголовки в запрос. Заголовок Origin ставит сам браузер и переписать его нельзя, а лишний свой заголовок только превращает простой запрос в предварительный.
Третье: теряют заголовки на ошибках. Ответ с кодом 500 или редирект, собранный в обход посредника, приходит без заголовков CORS, и настоящая ошибка сервера выглядит в консоли как проблема доступа.