Идентификатор сессии (Session ID) — случайная строка, которую веб-сервер генерирует при создании сессии и передаёт клиенту. Клиент возвращает идентификатор в каждом последующем запросе, позволяя серверу связать цепочку HTTP-запросов с одним пользователем. HTTP — протокол без состояния (stateless), и сессионный механизм — основной способ сохранить контекст между запросами.
Как работает
При успешной аутентификации сервер:
- Генерирует криптографически случайный Session ID (например, через
random_bytes(32)в PHP — 32 байта = 256 бит энтропии). - Сохраняет данные сессии в хранилище (файл, Redis, база данных) с ключом Session ID.
- Передаёт Session ID клиенту через Set-Cookie:
Set-Cookie: PHPSESSID=abc123def456; HttpOnly; Secure; SameSite=Strict; Path=/; Max-Age=3600. - Браузер автоматически включает cookie в каждый последующий запрос к тому же домену.
- Сервер читает cookie, ищет Session ID в хранилище и загружает данные пользователя.
Длина Session ID критична для безопасности. PHP до версии 7.1 генерировал предсказуемые 26-символьные ID. PHP 7.1+ по умолчанию генерирует 256 бит через CSPRNG. OWASP рекомендует минимум 128 бит случайных данных.
Cookie-флаги безопасности
- HttpOnly — блокирует доступ к cookie через JavaScript. Защищает от XSS-атак: даже при выполнении вредоносного JS злоумышленник не прочитает Session ID.
- Secure — отправлять cookie только по HTTPS. Без этого Session ID передаётся в открытом виде при HTTP-соединении.
- SameSite=Strict — cookie не отправляется при кросс-сайтовых запросах. Защита от CSRF-атак. SameSite=Lax — компромисс: разрешает GET-запросы при переходе по ссылке.
- Max-Age / Expires — срок жизни cookie. Без этих атрибутов — session cookie (удаляется при закрытии браузера).
История
Концепцию cookie для HTTP предложил Лу Монтулли (Lou Montulli) из Netscape в 1994 году для решения проблемы stateless-протокола при работе с корзинами покупок. Первая реализация появилась в Netscape Navigator 0.9 в октябре 1994 года. RFC 2109 (1997) формализовал механизм cookie. RFC 6265 (2011) обновил стандарт, добавив атрибуты HttpOnly и Secure. Атрибут SameSite стандартизирован в RFC 6265bis (2024). До SameSite CSRF-атаки через сессионные cookie были широко распространены.
Способы передачи Session ID
- Cookie — основной и рекомендуемый способ. Браузер отправляет автоматически. Поддерживает все флаги безопасности.
- URL-параметр —
?PHPSESSID=abc123. Устаревший, небезопасный метод: Session ID попадает в логи серверов, браузерную историю, HTTP Referer. Явно запрещён OWASP. - Скрытое поле формы —
<input type="hidden" name="session_id" value="...">. Редко, только для специфичных HTML-форм. - Заголовок X-Session-Token — для SPA и мобильных приложений, взаимодействующих с сервером через API.
Хранилища сессий на сервере
- Файловая система — PHP по умолчанию:
/tmp/sess_*. Не масштабируется горизонтально. Медленно при большом числе файлов. - Redis — in-memory хранилище с TTL. Чтение сессии за 0,1–1 мс. Стандарт для масштабируемых приложений. Конфигурация PHP:
session.save_handler=redis,session.save_path="tcp://127.0.0.1:6379". - Memcached — аналог Redis, без персистентности. Потеря данных при перезапуске.
- База данных — MySQL/PostgreSQL: медленнее Redis, но надёжнее при перезапуске. Используется для аудита доступа.
На что обращать внимание
Уязвимости Session ID входят в OWASP Top 10 под категорией «Broken Authentication». Помимо HttpOnly/Secure-флагов: при повышении привилегий (логин) обязательно регенерировать Session ID — иначе возможна session fixation атака (злоумышленник заранее устанавливает знакомый ему Session ID). В PHP: session_regenerate_id(true) при логине. Установить разумный timeout сессии (30–60 минут для веб-приложений, 24 часа для long-lived сессий). На стороне хостинга: для нескольких PHP-серверов за балансировщиком обязательно централизованное хранилище сессий (Redis) — иначе при переключении на другой сервер пользователь теряет сессию.