← Назад в словарь

CORS

CORS — совместное использование ресурсов между источниками

TL;DR

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

Краткое определение

CORS — механизм безопасности браузера, который ограничивает или разрешает запросы к ресурсам на другом домене/порту/протоколе на основе заголовков, отправленных сервером.

Оригинал и перевод

  • Язык: английский
  • Оригинал: CORS
  • Расшифровка: Cross-Origin Resource Sharing
  • Буквальный перевод: обмен ресурсами между разными источниками
  • Русские аналоги: кросс-доменные запросы, разделение ресурсов

Синонимы и варианты написания

  • Cross-Origin Resource Sharing
  • Кросс-доменная политика
  • Same-Origin Policy (противоположность)

Что такое Origin

Origin = протокол + домен + порт:

https://example.com:443  ← Origin
├──────┘ └─────┘ └──┘
  протокол домен порт

https://api.example.com ≠ https://example.com  (разные домены)
https://example.com:8080 ≠ https://example.com  (разные порты)
http://example.com ≠ https://example.com  (разные протоколы)

Где используется

  • SPA приложения: React/Vue/Astro фронтенд на отдельном домене обращается к API
  • REST/GraphQL API: публичные API для браузерных клиентов
  • Web fonts: загрузка шрифтов с CDN
  • WebGL textures: загрузка изображений для canvas
  • Fetch/XMLHttpRequest: кросс-доменные AJAX запросы

Когда это важно

CORS критичен в следующих сценариях:

  • Фронтенд и API на разных доменах: https://mysite.comhttps://api.mysite.com
  • Разработка на localhost: http://localhost:3000http://localhost:8080
  • Интеграции с третьими сторонами: виджеты, iframe, внешние API
  • Миграция с поддомена: www.site.rusite.ru (разные Origin!)

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

Простой запрос (Simple Request)

Браузер отправляет запрос с заголовком Origin и проверяет ответ:

# Запрос от браузера
GET /api/data HTTP/1.1
Origin: https://frontend.com

# Ответ от сервера
Access-Control-Allow-Origin: https://frontend.com
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Headers: Content-Type, Authorization

Браузер проверяет:

  1. Есть ли заголовок Access-Control-Allow-Origin?
  2. Совпадает ли он с Origin запроса (или *)?
  3. Если нет — блокирует ответ с ошибкой CORS.

Preflight запрос (OPTIONS)

Для сложных запросов браузер сначала отправляет OPTIONS:

# Preflight запрос
OPTIONS /api/data HTTP/1.1
Origin: https://frontend.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: Content-Type, Authorization

# Ответ сервера
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://frontend.com
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Max-Age: 86400  ← кэш preflight на 24 часа

Настройка CORS на сервере

Nginx: разрешить CORS для API

location /api/ {
    # Динамический Origin (проверяйте в production!)
    if ($http_origin ~* "^https://(www\.)?mysite\.com$") {
        add_header Access-Control-Allow-Origin $http_origin;
    }
    
    add_header Access-Control-Allow-Methods "GET, POST, OPTIONS, PUT, DELETE";
    add_header Access-Control-Allow-Headers "Content-Type, Authorization";
    add_header Access-Control-Allow-Credentials true;
    add_header Access-Control-Max-Age 86400;
    
    # Обработка preflight
    if ($request_method = OPTIONS) {
        add_header Content-Length 0;
        add_header Content-Type text/plain;
        return 204;
    }
    
    proxy_pass http://backend;
}

PHP: заголовки CORS

<?php
// Разрешить только конкретному домену
$allowedOrigin = 'https://frontend.com';
if (isset($_SERVER['HTTP_ORIGIN']) && $_SERVER['HTTP_ORIGIN'] === $allowedOrigin) {
    header("Access-Control-Allow-Origin: {$allowedOrigin}");
}

header('Access-Control-Allow-Methods: GET, POST, OPTIONS, PUT, DELETE');
header('Access-Control-Allow-Headers: Content-Type, Authorization');
header('Access-Control-Allow-Credentials: true');
header('Access-Control-Max-Age: 86400');

// Preflight запрос
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
    http_response_code(204);
    exit;
}

Node.js (Express): cors middleware

const cors = require('cors');

app.use(cors({
  origin: 'https://frontend.com',
  credentials: true,
  methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
  allowedHeaders: ['Content-Type', 'Authorization'],
  maxAge: 86400
}));

Заголовки CORS

Заголовки запроса (от браузера)

ЗаголовокОписание
OriginДомен, с которого сделан запрос
Access-Control-Request-MethodМетод запроса (для preflight)
Access-Control-Request-HeadersЗаголовки запроса (для preflight)

Заголовки ответа (от сервера)

ЗаголовокОписание
Access-Control-Allow-OriginКакой домен разрешён (или *)
Access-Control-Allow-MethodsРазрешённые методы
Access-Control-Allow-HeadersРазрешённые заголовки
Access-Control-Allow-CredentialsРазрешить cookies (true/false)
Access-Control-Max-AgeСколько кэшировать preflight (секунды)
Access-Control-Expose-HeadersКакие заголовки показать JS

Типичные ошибки CORS

  • Access-Control-Allow-Origin: * с credentials — нельзя использовать вместе
  • Несколько доменов через запятую — браузер примет только один
  • CORS защищает сервер — нет, это ограничение браузера, сервер должен сам проверять авторизацию
  • Блокировка в production — на localhost работало, а на проде нет (разные Origin)
  • Кэширование preflight слишком короткое — лишний OPTIONS запрос на каждый запрос

Аналоги и связанные термины

  • Same-Origin Policy — базовая политика безопасности (запрещает кросс-доменные запросы)
  • CSRF —跨站请求伪造 (другая уязвимость, часто путают с CORS)
  • JSONP — устаревший обход Same-Origin Policy (только GET)
  • Proxy server — обход CORS через прокси на том же домене

Смотри также (статьи на сайте)

Смотри также (сниппеты)

Смотри также (термины)

  • CSRF —跨站请求伪造 (другая уязвимость)
  • Same-Origin Policy — базовая политика безопасности
  • API — интерфейс программирования приложений

Мини-FAQ

CORS и CSRF — одно и то же?

Ответ: Нет. CORS — механизм браузера для разрешения кросс-доменных запросов. CSRF — уязвимость, когда чужой сайт заставляет браузер отправить запрос на ваш сервер. Это разные вещи.

Можно ли отключить CORS в браузере?

Ответ: Можно в режиме разработчика (флаги --disable-web-security), но никогда не делайте это в production. CORS защищает пользователей.

Почему на localhost работает, а на проде нет?

Ответ: Потому что http://localhost:3000 и https://mysite.com — разные Origin. Настройте CORS для production домена.

Access-Control-Allow-Origin: * — это безопасно?

Ответ: Для публичных API — да. Но если используете Access-Control-Allow-Credentials: true, то * нельзя — нужно указать конкретный домен.

Как отладить CORS ошибки?

Ответ:

  1. Откройте DevTools → Network
  2. Найдите запрос с ошибкой CORS
  3. Проверьте заголовки запроса (Origin) и ответа (Access-Control-Allow-Origin)
  4. Убедитесь, что они совпадают