flawopen.com/Vulnerabilities/Session Fixation & Cookie Hardening
Session Fixation: Session ID Rotation and Cookie Security
Imagine a traveler is tricked into using a baggage ticket number an attacker already knows. If the airline keeps that same number after check-in, the attacker may claim the bag. Session fixation has the same boundary failure: an application accepts a session identifier the attacker can make the victim use, then upgrades that identifier to an authenticated session without rotating it. Both conditions are required; a phishing link alone does not establish fixation unless the application accepts or can be made to set that identifier.
Core Concepts & Subsystem Terms
- Session fixation
- A session-management flaw in which an application accepts an identifier known to an attacker and keeps it when the victim authenticates.
- Session ID rotation
- Issue a fresh, unpredictable identifier when authentication changes session privilege. Preserve only the session data the application intends to keep.
- Cookie attributes
Securerestricts cookie transmission to HTTPS;HttpOnlyblocks JavaScript access to the cookie;SameSitecontrols some cross-site cookie sending. These flags address different risks and do not replace session-ID rotation.__Host-prefix- In supporting browsers, this prefix requires a Secure cookie set from HTTPS, with
Path=/and noDomainattribute. It helps prevent a sibling subdomain from setting a parent-domain cookie with the same name.
Step-by-Step Attack Flow
The attacker learns or chooses a session identifier
A vulnerable application or separate cookie-injection path lets the attacker obtain an identifier and make the victim browser send it. The exact delivery route depends on the application; an ordinary phishing URL does not work unless URL-based session IDs are accepted.
The victim uses the attacker-known identifier
The browser sends that identifier to the application, which treats it as a valid anonymous session. The attacker must be able to recognize or reuse the same identifier.
Authentication changes the session privilege
The victim signs in. If the application attaches the authenticated identity to the existing identifier instead of rotating it, that known identifier now refers to the authenticated session.
The attacker reuses the unchanged identifier
If the attacker can still send the identifier and the server has not invalidated it, the attacker may access the victim’s session. Session-ID rotation at the privilege change breaks this chain.
The Mechanism & Root Cause
Session fixation requires both attacker influence over the identifier the victim uses and failure to replace that identifier when authentication succeeds. Cookie attributes are valuable defense in depth, but none substitutes for rotation: HttpOnly limits script reads, Secure limits transport to HTTPS, SameSite reduces some cross-site cookie delivery, and __Host- constrains cookie scope in supporting browsers.
# 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
The Attack & Exploit Sequence
- 1Precondition: A separate weakness or supported feature lets the attacker influence the session identifier the victim browser will send.
- 2Known identifier: The attacker can recognize or reuse that same anonymous session ID.
- 3Authentication: The victim signs in while the browser continues sending the known ID.
- 4Missing rotation: The application upgrades the existing session instead of replacing its identifier.
- 5Conditional impact: The attacker can access the authenticated session only while the known ID remains valid and usable.
Defensive Engineering & Prevention Rules
- ✓Rotate at privilege changes: Issue a new unpredictable session ID on login and other privilege elevation; invalidate the previous ID according to the session framework’s documented behavior.
- ✓Use framework authentication APIs: Prefer the framework’s supported login/session integration (for Django,
django.contrib.auth.login()) over manually attaching identity fields to a session. - ✓Reject attacker-controlled session IDs: Do not accept session identifiers in URLs. Prevent sibling-subdomain cookie injection and test any custom cookie/session handling.
- ✓Set cookie protections for their actual purpose: Use
SecureandHttpOnly; consider a__Host-name withPath=/and noDomain. ChooseSameSite=LaxorStrictbased on legitimate cross-site sign-in flows; SameSite is not a replacement for CSRF tokens where needed. - ✓Verify the transition: In an automated test, record the anonymous ID, authenticate, assert the ID changed, and confirm the old ID cannot access the authenticated session.