Stage 7. Cookies
Cookie — это небольшой фрагмент состояния, который сервер записывает в браузер через Set-Cookie, а браузер потом автоматически отправляет обратно в подходящих запросах. На базовом уровне это выглядит просто, но в реальном продукте поведение cookie зависит от правил браузера, доменов, HTTPS, SameSite, прокси и структуры фронтенда. Поэтому cookie нужно рассматривать как отдельный контракт между браузером и сервером.
1. Как работает cookie по шагам
- Сервер возвращает
Set-Cookieв HTTP-ответе. - Браузер сохраняет cookie вместе с атрибутами (
Domain,Path,Secure,HttpOnly,SameSite,Max-Age). - В следующих запросах браузер сам решает, отправлять cookie или нет.
- Сервер получает cookie и связывает её с сессией или другим состоянием.
Главный момент для новичка: решение об отправке cookie принимает браузер по своим правилам, а не ваш controller. Поэтому на backend может «всё правильно», но cookie в запрос не приходит из-за атрибутов.
2. Минимальный пример установки cookie
Set-Cookie: sid=abc123; Path=/; HttpOnly; Secure; SameSite=Lax
Этот заголовок говорит браузеру: сохранить sid, отправлять по пути /, не давать читать значение JavaScript-коду (HttpOnly), передавать только по HTTPS (Secure), и ограничить cross-site поведение через SameSite=Lax.
3. Что означает каждый важный атрибут
| Атрибут | Что делает | Типичная ошибка |
|---|---|---|
HttpOnly | Запрещает доступ к cookie из скрипта страницы | Хранить сессионную cookie без HttpOnly |
Secure | Разрешает отправку только по HTTPS | Тестировать только на HTTP и ломаться в проде |
SameSite | Контролирует cross-site отправку cookie | Неверно выбрать режим для login/redirect потока |
Domain | Определяет, на какие хосты cookie действует | Случайно сделать cookie недоступной нужному поддомену |
Path | Ограничивает путь URL для отправки cookie | Установить на один путь, удалять на другом |
Max-Age/Expires | Управляет временем жизни cookie | Оставить бессрочную cookie без ротации |
4. Почему logout часто делают неправильно
Для удаления cookie недостаточно просто отправить пустое значение. Нужно удалить cookie в той же области действия, где она была создана: тот же Path и Domain.
Set-Cookie: sid=; Path=/; Max-Age=0; HttpOnly; Secure; SameSite=Lax
Если при удалении атрибуты не совпали, старая cookie может остаться в браузере, и пользователь увидит «странный» статус: UI показал logout, но часть запросов всё ещё проходит как у авторизованного пользователя.
5. Cookies, localStorage и session storage: когда что использовать
Cookie удобна для серверной сессии и автоматической отправки браузером. localStorage и sessionStorage не отправляются автоматически в HTTP-запросах и читаются скриптами страницы. Из-за этого чувствительные сессионные идентификаторы обычно хранят именно в HttpOnly cookie, а не в localStorage.
6. Что важно проверить перед релизом
- Все auth-cookie имеют
HttpOnlyиSecure? SameSiteсоответствует вашему реальному login-flow?- Установка и удаление cookie симметричны по
DomainиPath? - Есть тесты для cross-subdomain и logout сценариев?
- Значения cookie маскируются в логах?
Практический сценарий
Команда запустила новый logout endpoint и увидела, что часть пользователей после «выхода» всё равно открывает защищённые страницы без повторного входа. Анализ показал: cookie создавалась с Path=/, а удалялась с Path=/api. Браузер считал это разными областями действия и сохранял исходную cookie. После выравнивания Path и добавления e2e-проверки logout на нескольких маршрутах проблема исчезла. Этот кейс показывает, что в cookie-сценариях именно атрибуты определяют реальное поведение, а не только код бизнес-логики.