Учебник веб-разработки
Разделы учебника
На этой странице

VII. HTTP и API

Браузерные границы: origin, cookies, CORS и CSRF

Оглавление · HTTP

Origin — тройка scheme, host, port. https://site.example и https://cms.example — разные origins, хотя могут быть одним site для правил cookies. Same-site и same-origin нельзя подменять друг другом. Серверный fetch из Next.js не ограничивается CORS браузера; ошибка CORS не доказывает отказ CMS.

Три независимых решения

Аутентификация устанавливает, кто делает запрос. Авторизация разрешает конкретную операцию над конкретным объектом. CORS определяет, может ли браузерный JavaScript читать cross-origin ответ. Злоумышленник может вызвать API вне браузера; разрешённый Origin не является учётной записью.

Исходник схемы
sequenceDiagram
  participant B as Браузер другого origin
  participant A as API
  B->>A: OPTIONS, метод и заголовки
  A-->>B: Разрешённые origin, методы, заголовки
  B->>A: Запрос, если preflight разрешён
  Note over A: Отдельно проверка входа, личности и прав
  A-->>B: Ответ

Некоторые запросы отправляются без preflight, например обычная HTML-форма. CORS может закрыть чтение ответа, когда эффект уже выполнен. mode: "no-cors" даёт opaque ответ и не превращает закрытый API в читаемый. Для разрешённого credentialed fetch нужен конкретный Access-Control-Allow-Origin, не *, и Access-Control-Allow-Credentials: true. При отражении разрешённого Origin добавляют Vary: Origin, чтобы общий кеш не смешал ответы разных origins.

Cookies и токены

Cookie браузер отправляет автоматически по правилам домена, пути, Secure, SameSite и запроса. HttpOnly запрещает чтение из JS, но не отправку cookie. Secure требует HTTPS, SameSite ограничивает cross-site отправку. SameSite=None требует Secure; политика браузера может дополнительно ограничить third-party cookies. Для cross-origin fetch обычно нужен credentials: "include", но он не отменяет SameSite и CORS. Не рассчитывайте на Path как на изоляцию доверия приложений.

Bearer token передают явно в Authorization. Серверный CMS token проекта остаётся на сервере; его нельзя помещать в Client Component, публичную переменную NEXT_PUBLIC_*, HTML или URL. URL попадает в историю и логи. Доступ к Strapi admin не даёт автоматически права произвольному читателю сайта.

CSRF — использование автоматически прикладываемых полномочий для чужого запроса. Для cookie-authenticated изменения нужны согласованные меры: запрет эффектов в GET, проверка Origin/Referer по allowlist и CSRF token либо другой принятый механизм. SameSite — дополнительный барьер, а не универсальное доказательство. XSS способен выполнять код внутри разрешённого origin, поэтому CSRF-защита не заменяет безопасный вывод контента. HttpOnly уменьшает кражу cookie, но не возможности XSS отправлять действия от имени пользователя.

Лаборатория двух origins

В отдельной локальной среде откройте статическую учебную страницу на http://127.0.0.1:4181 и собственный тестовый HTTP API на :4182. Не используйте CMS credentials или production endpoints.

  1. Вызовите GET через fetch без CORS-ответа: сравните Network, Console и серверный лог. Сервер мог получить запрос, хотя JS не прочитал тело.
  2. Разрешите ровно http://127.0.0.1:4181; повторите GET. localhost:4181 является другим origin, проверьте запрет отдельно.
  3. Добавьте JSON POST или нестандартный заголовок: найдите OPTIONS до POST. Запретите метод в ответе preflight и убедитесь, что POST не отправился.
  4. Сравните POST формы без custom headers: он может уйти без preflight. Поэтому тестовый обработчик не выполняет реальный эффект без проверки прав.
  5. При cookie-auth сравнении отдельно фиксируйте hostname, SameSite, Secure, credentials и browser policy. HTTPS-cookie опыт требует локального HTTPS; результаты plain HTTP нельзя переносить на production.
  6. Вызовите тот же API из Node/curl: успешное чтение вне браузера не исправляет CORS.

Приёмка: таблица «запрос отправлен / эффект разрешён / ответ читается JS» для каждого случая. Это ручной браузерный опыт; happy-dom и серверные тесты не воспроизводят полную cookie/CORS-политику настоящего браузера.

В Atmanki браузер получает публичный контент через сайт, сервер обращается к CMS. Webhook проверяет отдельный секрет; это не пользовательская сессия и не универсальная модель auth для будущих mutations. Ограничивайте размер входа, валидируйте форму и проверяйте права прежде эффекта, независимо от транспорта.

Источники: CORS, cookies, CSRF.