Где должна быть звездочка в CORS, кто ее возвращает и как браузер проверяет разрешенные домены?
Что проверяют
Понимаете ли вы, что CORS проверяет браузер, а разрешение выдаёт сервер, и чем * отличается от конкретного origin. Следом спрашивают, почему со звёздочкой не уходят куки и зачем нужен preflight.
Как отвечать
Звёздочка ставится в заголовке ответа Access-Control-Allow-Origin: *. Возвращает её сервер, к которому идёт запрос: само API или то, что стоит перед ним (nginx, API-шлюз, CDN). Фронтенд выставить его не может.
Как проверяет браузер:
- Origin: к кросс-доменному запросу браузер сам добавляет заголовок
Originсо схемой, хостом и портом страницы.https://app.ruиhttp://app.ru:8080для него разные источники; - простой запрос (
GET,HEAD,POSTбез своих заголовков и сContent-Typeиз трёх разрешённых) уходит сразу. Сервер его обрабатывает, а браузер смотрит на ответ: еслиAccess-Control-Allow-Originравен*или точно совпадает сOrigin, JS получает ответ, иначе видит ошибку; - preflight: для
PUT,PATCH,DELETE, заголовкаAuthorizationилиContent-Type: application/jsonбраузер сначала шлётOPTIONSсAccess-Control-Request-MethodиAccess-Control-Request-Headers. Сервер отвечаетAccess-Control-Allow-MethodsиAccess-Control-Allow-Headers, а черезAccess-Control-Max-Ageразрешение можно закэшировать; - с куками (
credentials: 'include') звёздочка запрещена: нужен точный origin иAccess-Control-Allow-Credentials: true.
Список доменов через запятую в Access-Control-Allow-Origin не работает. Сервер сверяет Origin со своим белым списком, возвращает совпавшее значение и добавляет Vary: Origin, чтобы кэш не отдал чужой ответ.
Где спотыкаются
Считают, что CORS защищает сервер. Простой запрос до сервера доходит и выполняется, браузер лишь прячет ответ. curl и Postman CORS не проверяют вовсе.
Лечат ошибку через mode: 'no-cors'. Запрос уйдёт, но ответ станет непрозрачным и нечитаемым. В разработке правильнее прокси dev-сервера, например server.proxy в Vite.
Делают на бэкенде «отражение»: возвращают любой пришедший Origin вместе с Access-Control-Allow-Credentials: true. Это хуже звёздочки: любой сайт сможет читать данные от имени залогиненного пользователя.