Что такое CORS и как этот механизм работает в браузере

Ответ

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

Проблема, которую решает CORS

По умолчанию браузеры следуют политике одинакового источника (Same-Origin Policy, SOP), которая запрещает скриптам делать запросы к другому домену, протоколу или порту. Это защищает пользователей от вредоносных сайтов, которые могли бы читать данные с других открытых вкладок (например, из онлайн-банка).

CORS предоставляет серверам контролируемый способ ослабить эту политику и разрешить кросс-доменные запросы от доверенных источников.

Как работает CORS

  1. Простой запрос (например, GET или POST с простыми заголовками): браузер отправляет запрос, добавляя заголовок Origin с указанием домена-инициатора.
  2. Ответ сервера: Если сервер разрешает запрос с этого домена, он возвращает ответ с заголовком Access-Control-Allow-Origin: <домен> или Access-Control-Allow-Origin: * (разрешить всем).
  3. Предварительный запрос (Preflight Request): для "сложных" запросов (например, с методами PUT, DELETE или нестандартными заголовками) браузер сначала отправляет OPTIONS-запрос на тот же URL.
    • Сервер в ответ должен прислать заголовки, разрешающие метод, заголовки и источник (Access-Control-Allow-Methods, Access-Control-Allow-Headers).
    • Если preflight-запрос успешен, браузер отправляет основной запрос.

Пример настройки CORS в FastAPI (Python)

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

app = FastAPI()

# Список доменов, которым разрешены запросы
origins = [
    "http://localhost:3000",
    "https://my-frontend-app.com",
]

# Добавление middleware для обработки CORS
app.add_middleware(
    CORSMiddleware,
    allow_origins=origins, # Разрешенные домены
    allow_credentials=True, # Разрешить cookies
    allow_methods=["GET", "POST"], # Разрешенные HTTP-методы
    allow_headers=["Authorization"], # Разрешенные HTTP-заголовки
)

@app.get("/api/data")
def get_data():
    return {"message": "This data is accessible via CORS"}

Если браузер не получит нужные заголовки от сервера, он заблокирует ответ, и в консоли разработчика появится ошибка CORS.