Как происходит проверка CORS в браузере?

Ответ

CORS (Cross-Origin Resource Sharing) — это механизм безопасности, реализованный в браузерах, который контролирует запросы с одного домена (origin) к ресурсам другого домена. Сервер должен явно разрешить такие кросс-доменные запросы.

Последовательность проверки:

  1. Определение "простого" (simple) запроса: Браузер сразу отправляет основной запрос (без предварительной проверки), если он удовлетворяет всем критериям:

    • Методы: GET, POST, HEAD.
    • Заголовки: Только стандартные (Accept, Accept-Language, Content-Language, Content-Type с значениями application/x-www-form-urlencoded, multipart/form-data, text/plain).
  2. Предварительный запрос (Preflight Request) для "непростых" запросов: Если запрос не является "простым" (например, использует кастомный заголовок X-API-Key или метод PUT), браузер автоматически отправляет предварительный запрос методом OPTIONS на тот же URL.

    OPTIONS /api/data HTTP/1.1
    Origin: https://myfrontend.com
    Access-Control-Request-Method: PUT
    Access-Control-Request-Headers: X-API-Key, Content-Type
  3. Ответ сервера на Preflight: Сервер должен ответить с заголовками, разрешающими запрос:

    HTTP/1.1 204 No Content
    Access-Control-Allow-Origin: https://myfrontend.com
    Access-Control-Allow-Methods: GET, POST, PUT
    Access-Control-Allow-Headers: X-API-Key, Content-Type
    Access-Control-Max-Age: 86400 // Кэшировать ответ на 24 часа
  4. Основной запрос: Только если предварительный ответ удовлетворителен, браузер отправляет основной запрос. В ответе на основной запрос также должен присутствовать заголовок Access-Control-Allow-Origin.

Настройка в ASP.NET Core:

// В Program.cs
app.UseCors(builder => builder
    .WithOrigins("https://trusted-domain.com") // Конкретный origin
    .AllowAnyMethod()                          // Или .AllowMethods("GET", "POST")
    .AllowAnyHeader()                          // Или .WithHeaders("X-API-Key")
    .AllowCredentials());                      // Разрешить куки/авторизацию
// Важно: при использовании AllowCredentials() нельзя использовать WithOrigins("*").

Важно: CORS — это защита браузера. Инструменты вроде Postman или curl отправляют запросы напрямую и не выполняют проверки CORS.

Ответ 18+ 🔞

А, CORS, блядь! Ну это ж классика, ёпта! Сидишь такой, пишешь фронтенд, всё работает, а потом — бац! — в консоли браузера красным: «CORS policy blocked». И ты такой: «Какого хуя? У меня же API отвечает!»

Вот смотри, это такая защита в браузерах, чтобы один сайт не мог тайком с другого сайта данные стянуть. Представь, зашёл ты на «левый-сайт.ру», а он в фоне запросил твою переписку из ВК. Пиздец, да? Вот чтобы такого не было, браузер и спрашивает у сервера: «Мужик, можно этому сайту к тебе обращаться?»

Как эта хуйня работает, по шагам:

  1. Простые запросы. Если ты шлёшь обычный GET или POST с простыми заголовками — браузер сразу отправляет запрос, без лишних телодвижений. Как будто стучишь в дверь и сразу заходишь.

  2. А вот если ты выёбываешься — ставишь кастомный заголовок X-API-Key или метод PUT используешь — браузер тебе сразу: «Стоять, блядь!». И шлёт предварительный запрос (preflight) методом OPTIONS. Это как спросить: «Чувак, можно я к тебе зайду и вот так вот сделаю?». Выглядит это так:

    OPTIONS /api/data HTTP/1.1
    Origin: https://мой-фронтенд.com
    Access-Control-Request-Method: PUT
    Access-Control-Request-Headers: X-API-Key, Content-Type
  3. Сервер должен ответить по-братски. Мол, да, вали, я тебя знаю.

    HTTP/1.1 204 No Content
    Access-Control-Allow-Origin: https://мой-фронтенд.com
    Access-Control-Allow-Methods: GET, POST, PUT
    Access-Control-Allow-Headers: X-API-Key, Content-Type
    Access-Control-Max-Age: 86400 // Чтоб не спамить OPTIONS, кэш на сутки
  4. И только тогда, получив добро, браузер отправит твой настоящий, основной запрос. И в ответе на него тоже должен быть заголовок Access-Control-Allow-Origin. А то опять ругань будет.

Как это в ASP.NET Core настроить, чтобы не бомбило:

// В Program.cs
app.UseCors(builder => builder
    .WithOrigins("https://мой-доверенный-сайт.com") // Чётко указываешь, кто может
    .AllowAnyMethod()                          // Или точечно: .AllowMethods("GET", "POST")
    .AllowAnyHeader()                          // Или .WithHeaders("X-API-Key")
    .AllowCredentials());                      // Если с куками/авторизацией работаешь
// Важный момент, запомни как «Отче наш»: если AllowCredentials() используешь, WithOrigins("*") уже нельзя. Нахуй такую щедрость, безопасность важнее.

И главное, что всех новичков вводит в ступор: CORS — это защита браузера, ёпта! Postman, curl, да любой другой инструмент — им похуй на эти заголовки, они шлют запросы куда хотят. А браузер — тот ещё контролёр, блядь. Так что если в Постмане всё летает, а в браузере нет — ищи проблему именно в этих заголовках, а не в логике API.