flawopen.com/Vulnerabilities/Фиксация сессии и защита cookie
Фиксация сессии: смена ID при входе (CWE-384)
Представьте, что путешественника убеждают воспользоваться номером багажной квитанции, который уже известен атакующему. Если авиакомпания сохранит этот номер после регистрации багажа, атакующий сможет забрать чемодан. При фиксации сессии приложение принимает идентификатор, который атакующий может навязать жертве, а затем без смены превращает его в аутентифицированную сессию. Нужны оба условия; обычная фишинговая ссылка сама по себе не фиксирует сессию, если приложение не принимает этот идентификатор и не позволяет его установить.
Основные понятия и термины подсистемы
- Фиксация сессии
- Ошибка управления сессиями: приложение принимает известный атакующему идентификатор и сохраняет его после аутентификации жертвы.
- Смена ID сессии
- Выдавайте новый непредсказуемый идентификатор при повышении привилегий сессии. Сохраняйте только те данные сессии, которые действительно нужны приложению.
- Атрибуты cookie
Secureограничивает передачу cookie протоколом HTTPS;HttpOnlyзапрещает чтение cookie из JavaScript;SameSiteуправляет частью межсайтовой отправки cookie. Эти атрибуты решают разные задачи и не заменяют смену ID.- Префикс
__Host- - В поддерживающих браузерах требует установить Secure-cookie через HTTPS с
Path=/и без атрибутаDomain. Это помогает не дать соседнему поддомену установить одноимённую cookie для родительского домена.
Пошаговая последовательность атаки
Атакующий получает или выбирает идентификатор сессии
Отдельная уязвимость или функция позволяет атакующему получить ID и заставить браузер жертвы отправлять его. Способ зависит от приложения; обычная фишинговая ссылка не сработает, если приложение не принимает ID сессии в URL.
Жертва использует известный атакующему идентификатор
Браузер отправляет ID приложению, которое считает его допустимой анонимной сессией. Атакующий должен иметь возможность распознать или повторно использовать тот же ID.
Аутентификация повышает привилегии сессии
Жертва входит в систему. Если приложение связывает аутентифицированную личность с прежним ID, не меняя его, этот известный идентификатор начинает обозначать аутентифицированную сессию.
Атакующий повторно использует прежний ID
Если атакующий всё ещё может отправить ID и сервер его не аннулировал, возможно использование сессии жертвы. Смена ID при повышении привилегий разрывает эту цепочку.
Механизм и первопричина
Для фиксации сессии нужны и влияние атакующего на идентификатор, который использует жертва, и отсутствие его замены после входа. Атрибуты cookie дополняют защиту, но не заменяют смену ID: HttpOnly ограничивает чтение скриптами, Secure требует HTTPS, SameSite сокращает часть межсайтовых отправок, а __Host- ограничивает область cookie в поддерживающих браузерах.
# VULNERABLE: custom session code keeps the pre-authentication ID.
def login_view(request):
user = authenticate(request, request.POST["username"],
request.POST["password"])
if user is not None:
# BUG: privilege changes, but the session ID does not.
request.session["user_id"] = user.pk
request.session["authenticated"] = True
return redirect("/account/")
return redirect("/login/")
# HARDENED: Django login() rotates the session key on authentication.
from django.contrib.auth import authenticate, login
def login_view(request):
user = authenticate(request, request.POST["username"],
request.POST["password"])
if user is not None:
# Uses Django's supported authentication/session integration.
login(request, user)
return redirect("/account/")
return redirect("/login/")
# settings.py: use HTTPS, host-only scope, and a deliberate SameSite policy.
SESSION_COOKIE_NAME = "__Host-sessionid"
SESSION_COOKIE_SECURE = True
SESSION_COOKIE_HTTPONLY = True
SESSION_COOKIE_SAMESITE = "Lax"
SESSION_COOKIE_PATH = "/"
SESSION_COOKIE_DOMAIN = None
Сценарий атаки и концептуальный пример
- 1Предусловие: Отдельная уязвимость или функция позволяет атакующему влиять на ID, который отправит браузер жертвы.
- 2Известный ID: Атакующий может распознать или повторно использовать тот же анонимный ID сессии.
- 3Аутентификация: Жертва входит в систему, а браузер продолжает отправлять известный ID.
- 4Нет смены: Приложение повышает привилегии существующей сессии, а не заменяет её идентификатор.
- 5Условный эффект: Атакующий может использовать сессию, только пока известный ID остаётся действительным и пригодным к использованию.
Инженерные правила предотвращения и защиты
- ✓Меняйте ID при смене привилегий: Выдавайте новый непредсказуемый ID при входе и других повышениях привилегий; аннулируйте прежний согласно документации фреймворка.
- ✓Используйте API аутентификации фреймворка: Предпочитайте штатную интеграцию входа и сессий (в Django —
django.contrib.auth.login()), а не ручную запись идентификаторов личности в сессию. - ✓Отклоняйте ID под контролем атакующего: Не принимайте ID сессии в URL. Предотвращайте внедрение cookie с соседних поддоменов и проверяйте пользовательскую логику cookie/сессий.
- ✓Настраивайте атрибуты cookie по назначению: Используйте
SecureиHttpOnly; рассмотрите префикс__Host-сPath=/и безDomain. ВыбирайтеSameSite=LaxилиStrictс учётом законных межсайтовых сценариев входа; SameSite не заменяет CSRF-токены, когда они нужны. - ✓Проверяйте переход: В автоматическом тесте зафиксируйте анонимный ID, выполните аутентификацию, проверьте смену ID и убедитесь, что старый ID не открывает аутентифицированную сессию.