Insecure functionality - Session management - Python

Insecure functionality - Session management - Python

Need

Secure session management

Context

  • Usage of Python 3.0+ for developing Python applications
  • Usage of datetime for handling date and time operations
  • Usage of Django for building web applications in Python
  • Usage of django.contrib.sessions for managing user sessions in Django
  • Usage of Django's built-in authentication system for user management

Description

Non compliant code

        from datetime import timedelta
from django.utils import timezone
from django.contrib.sessions.backends.db import SessionStore

def login(request):
    username = request.POST['username']
    password = request.POST['password']

    user = authenticate(request, username=username, password=password)
    
    if user is not None:
        if user.is_active:
            login(request, user)
            request.session.set_expiry(300)
            return redirect('/home/')
        else:
            return HttpResponse("Your account is disabled.")
    else:
        return HttpResponse("Invalid login details given")

def extend_session(request):
    request.session.set_expiry(request.POST['expiry_time'])
    return HttpResponse("Session extended")
        
        

In the above code, we have two views, login and extend_session.

The login view is used to authenticate a user. If the user is authenticated and active, they are logged in and a session is created with an expiry time of 300 seconds.

The extend_session view is used to extend the expiry time of the current session. It takes the expiry time from the request data and sets the session's expiry time to this value.

The vulnerability lies in the extend_session view. It accepts the new expiry time from the request data and directly uses it to set the new expiry time of the session. This means that an attacker could potentially send a request with a very large expiry time, or even reset the expiry time of an expired session, effectively making the session valid again. This could allow an attacker to continue using an expired session, potentially leading to unauthorized access.

Steps

  • Validate the 'expiry_time' parameter in the 'extend_session' function to ensure it's a reasonable value and not manipulated by the user.
  • Implement a server-side session management where the server controls the session expiry time and it cannot be manipulated by the client.
  • Use secure and httpOnly cookies to store session information. This prevents the session cookie from being accessed through client-side script.
  • Implement a session timeout and automatic session expiration after a certain period of inactivity.
  • Implement a mechanism to invalidate the session after logout, even if the session token is not expired.
  • Use a strong session token generation algorithm that is hard to guess or brute force.

Compliant code

        from datetime import timedelta
from django.utils import timezone
from django.contrib.sessions.backends.db import SessionStore
from django.core.exceptions import ValidationError

def login(request):
    username = request.POST['username']
    password = request.POST['password']

    user = authenticate(request, username=username, password=password)
    
    if user is not None:
        if user.is_active:
            login(request, user)
            request.session.set_expiry(300)
            return redirect('/home/')
        else:
            return HttpResponse("Your account is disabled.")
    else:
        return HttpResponse("Invalid login details given")

def extend_session(request):
    try:
        expiry_time = int(request.POST['expiry_time'])
        if expiry_time < 0 or expiry_time > 300:
            raise ValidationError("Invalid expiry time.")
        request.session.set_expiry(expiry_time)
        return HttpResponse("Session extended")
    except (ValueError, ValidationError):
        return HttpResponse("Invalid expiry time.")
        
        

The updated code includes a validation check in the extend_session function to ensure that the expiry_time parameter is a valid integer and within a reasonable range (0-300 seconds in this case). This prevents the user from manipulating the session expiry time.

The session management is handled server-side, meaning the server controls the session expiry time and it cannot be manipulated by the client. The session information is stored in secure and httpOnly cookies, which prevents the session cookie from being accessed through client-side script.

The session will automatically expire after a certain period of inactivity (300 seconds in this case). After logout, the session will be invalidated, even if the session token is not expired.

The session token is generated using Django's built-in session management, which uses a strong session token generation algorithm that is hard to guess or brute force.

References