Session Fixation - Python

Session Fixation - Python

Need

Prevention of session hijacking

Context

  • Usage of Python 3 for developing applications and scripts
  • Usage of Django for building web applications in Python

Description

Non compliant code

        from django.contrib.auth import authenticate, login

def login_view(request):
    username = request.POST['username']
    password = request.POST['password']
    user = authenticate(request, username=username, password=password)
    if user is not None:
        login(request, user)
        return JsonResponse({'status': 'success'})
    else:
        return JsonResponse({'status': 'error'})
        
        

The above Django view handles user login. The login_view function retrieves the username and password from the request, and attempts to authenticate the user with these credentials. If the user is authenticated successfully, the login function is called, which logs the user in and attaches their user session to the current request.

The vulnerability here lies in the login function. In Django, when a user logs in, their user session is attached to the current request. However, the session ID in the cookie does not change after a successful login. This means that if an attacker is able to obtain a user's session cookie before they log in, they can continue to use this session cookie to access the user's session even after the user has logged in.

This is known as a Session Fixation attack. The attacker fixes the user's session ID before they log in, and then uses this session ID to hijack the user's session after they have logged in. Because the session ID does not change during login, the attacker can continue to access the user's session as long as the session is valid.

Steps

  • Import the update_session_auth_hash function from django.contrib.auth.
  • After a successful login, call the update_session_auth_hash function with the request and user as arguments. This will create a new session ID for the user, preventing session fixation attacks.

Compliant code

        from django.contrib.auth import authenticate, login, update_session_auth_hash

def login_view(request):
    username = request.POST['username']
    password = request.POST['password']
    user = authenticate(request, username=username, password=password)
    if user is not None:
        login(request, user)
        update_session_auth_hash(request, user)  # Update the session ID after successful login
        return JsonResponse({'status': 'success'})
    else:
        return JsonResponse({'status': 'error'})
        
        

The updated code now includes a call to the update_session_auth_hash function from Django's authentication framework. This function is called immediately after a successful login.

The update_session_auth_hash function takes two arguments: the current request and the user who has just been authenticated. It updates the session hash for the authenticated user, effectively creating a new session ID. This is a crucial step in preventing session fixation attacks.

In a session fixation attack, an attacker tricks a victim into using a session ID known to the attacker. Once the victim logs in with that session ID, the attacker can use it to hijack the victim's session. By changing the session ID after login, we ensure that even if an attacker has the old session ID, they cannot use it to hijack the session after the victim logs in.

The rest of the code remains the same. The username and password are extracted from the POST request, and the user is authenticated. If the authentication is successful, the user is logged in, the session ID is updated, and a JSON response with a status of 'success' is returned. If the authentication fails, a JSON response with a status of 'error' is returned.

References