Можно ли делать запросы с сайта на другой домен и как работает CORS?
Что проверяют
Понимаете ли вы, что CORS это не защита сервера, а способ ослабить политику одного источника. Проверяют, кто блокирует ответ и в какой момент. Следом уточняют, когда браузер шлёт предварительный OPTIONS и почему Access-Control-Allow-Origin: * не работает с куками.
Как отвечать
Начните с запрета: политика одного источника не даёт скрипту прочитать ответ чужого источника. Источник это тройка протокол, хост, порт, поэтому https://app.example.com и https://api.example.com разные источники. CORS это набор заголовков, которыми сервер разрешает браузеру отдать ответ скрипту.
- простой запрос:
GET,HEADилиPOSTсContent-Typeиз спискаtext/plain,application/x-www-form-urlencoded,multipart/form-data. Уходит сразу, браузер добавляетOriginи сверяетAccess-Control-Allow-Originв ответе; - предварительный запрос: всё остальное:
PUT,DELETE,PATCH,Content-Type: application/json, свой заголовок вродеAuthorization. Браузер сначала шлётOPTIONSсAccess-Control-Request-MethodиAccess-Control-Request-Headers, а разрешение кэшируется поAccess-Control-Max-Age(Chromium обрезает до 7200 секунд); - куки и авторизация:
fetchсcredentials: "include"требуетAccess-Control-Allow-Credentials: trueи конкретный источник вAccess-Control-Allow-Origin, звёздочка тут запрещена; - чтение заголовков: скрипту видны только базовые, остальные перечисляются в
Access-Control-Expose-Headers.
Скажите про Vary: Origin: без него CDN отдаст одному источнику заголовки, закэшированные для другого. И про то, что простой запрос сервер выполняет по-настоящему: браузер лишь прячет ответ, данные уже изменены. От CSRF защищает не CORS, а SameSite и токены.
Где спотыкаются
Говорят, что CORS защищает сервер от чужих запросов. Он ограничивает только браузерный код, curl и любой бэкенд ходят куда угодно.
Лечат ошибку прокси на фронте и на этом останавливаются. Прокси убирает симптом при разработке, а спрашивали про механизм.
Путают preflight с авторизацией: OPTIONS уходит без кук и заголовка Authorization, и если бэкенд закрыл его аутентификацией, всё падает до основного запроса.