Фиксация сессии — это когда жертва входит с ID, который подготовил атакующий. Вот как она работает и как её надёжно предотвратить (без шагов атаки).
Почему это работает
Причина — в конструкции, где ID сессии не меняется при входе. Если он не меняется, ID, который атакующий знал до входа, всё ещё работает как «аутентифицированный» после входа.
Это может сочетаться с CSRF или XSS, но суть самой фиксации — одна вещь: ID не был регенерирован при входе.
Руководство японского IPA (Агентства по развитию информационных технологий) «How to Secure Your Website» относит это к одной из форм ненадлежащего управления сессиями и говорит, что следить за этим нужно на любом сайте с функцией входа. Коренное исправление по нему — начинать новую сессию после успешного входа.
Фиксация, перехват и CSRF
Эти три легко перепутать. Все они злоупотребляют состоянием «пользователь вошёл», но различаются тем, что есть у атакующего, и тем, какая защита работает.
| Пункт | Фиксация сессии | Перехват сессии | CSRF |
|---|---|---|---|
| Что есть у атакующего | ID, который он подготовил (известен с самого начала) | Украденный, уже выданный ID | Никакого ID |
| Что происходит с жертвой | Она входит с подброшенным ID | У неё крадут выданный ID | Её заставляют отправить непреднамеренный запрос |
| Основная защита | Регенерация ID при входе | HttpOnly/Secure, защита от XSS, короткий срок жизни | CSRF-токены, SameSite |
Фиксацию устраняет в корне один шаг — регенерация ID при входе.
Защита: регенерируйте ID при входе
Регенерируйте ID сессии при успешном входе (самое важное)
Не принимайте ID сессии через URL
Выставьте флаги cookie
HttpOnly (JS не может читать), Secure (только HTTPS) и SameSite (ограничивает межсайтовую отправку). Это вместе ослабляет связанные пути перехвата.Разумно завершайте сессии
Руководство OWASP по управлению сессиями рекомендует регенерировать ID при каждой смене привилегий и использовать «строгий» механизм, который принимает только ID, сгенерированные самим сервером. «Нестрогий» механизм, принимающий неизвестный ID, принесённый извне, оставляет возможность принять ID, выбранный атакующим.
Что делают популярные фреймворки по умолчанию
Большинство фреймворков регенерируют ID автоматически, если вы используете их стандартный вход. Риск появляется, когда вы пишете вход сами или отключаете защиту по умолчанию.
| Среда | Поведение по умолчанию | Что проверить, если пишете сами |
|---|---|---|
| PHP (обычные сессии) | Сам не регенерирует; session.use_strict_mode по умолчанию 0 | Вызывайте session_regenerate_id(true) при успешном входе; установите use_strict_mode в 1 |
| Laravel | Регенерирует автоматически при аутентификации, если используете стартовый набор или Fortify | Если пишете вход вручную, вызывайте $request->session()->regenerate() |
| Spring Security | Включено по умолчанию (changeSessionId на Servlet 3.1+) | Убедитесь, что никто не выставил sessionFixation().none() |
В PHP настройки, передающие ID сессии в URL (включение session.use_trans_sid, отключение session.use_only_cookies), объявлены устаревшими в PHP 8.4. Если вы переносите старый конфигурационный файл, пересмотрите их.
Как проверить свой сайт
На сайте, которым вы управляете, проверьте эти четыре вещи. Хватит инструментов разработчика.
- В инструментах разработчика на вкладке «Application» (в Firefox — «Хранилище») запишите значение сессионного cookie, затем посмотрите снова после входа. Если оно не изменилось, ID не регенерируется при входе
- Проверьте, что URL страницы входа и страниц после входа не содержат ID сессии вроде
PHPSESSID=или;jsessionid= - На той же панели проверьте, что у сессионного cookie есть
HttpOnly,SecureиSameSite - После выхода верните старое значение cookie и перезагрузите страницу; убедитесь, что вы снова не вошли
Атрибуты cookie проверяет и аудит безопасности сайта — для сайтов, владение которыми вы подтвердили. Если внести проверку 1 в автоматический тест на любые изменения потока входа, вы сразу заметите, если регенерация пропадёт.
Мнение этого сайта: не отключайте «регенерацию» во фреймворке
Фиксация сессии в основном предотвращается одним шагом: регенерацией ID при входе, а не сложным самописным кодом. Ключ в том, чтобы случайно не отключить и не забыть вызвать механизм, который ваш фреймворк уже предоставляет. Использовать безопасные значения по умолчанию проверенной реализации лучше, чем самому собирать управление сессиями. На этом сайте мы держимся правила «не пишите аутентификацию/работу с ключами сами; не отключайте безопасные значения по умолчанию». Как и с IDOR, аутентификация/авторизация должны обеспечиваться механизмом на каждом запросе.
Источники (первичные)
- IPA, «How to Secure Your Website», 1.4 Ненадлежащее управление сессиями — ipa.go.jp (начинать новую сессию после входа; не помещать ID в URL; на японском)
- OWASP Session Management Cheat Sheet — cheatsheetseries.owasp.org (регенерация при смене привилегий, строгий механизм, атрибуты cookie)
- MITRE CWE-384: Session Fixation — cwe.mitre.org
- Руководство PHP, «Runtime Configuration» (сессии) — php.net (значения по умолчанию, например
use_strict_mode; устаревание в 8.4) - Документация Laravel, «HTTP Session» — laravel.com / Spring Security, «Authentication Persistence and Session Management» — docs.spring.io
Читать дальше
- Глоссарий: Что такое CSRF · Что такое XSS · Что такое IDOR · Что такое JWT
- Основы: Аутентификация и авторизация