Concurrent sessions - Python

Concurrent sessions - Python

Need

Enforce session management and limit concurrent user sessions

Context

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

Description

Non compliant code

        from django.contrib.auth import authenticate, login

def login_view(request):
    # Get the username and password from the POST request
    username = request.POST['username']
    password = request.POST['password']
    
    # Authenticate the user
    user = authenticate(request, username=username, password=password)
    
    # If the user is authenticated successfully
    if user is not None:
        # Login the user
        login(request, user)
        return HttpResponse("You are now logged in.")
    else:
        return HttpResponse("Invalid username or password.")
        
        

The above Python-Django code is a basic example of a login view function that handles user authentication. It takes a POST request with a username and password, and uses Django's built-in authenticate function to verify the credentials. If the authentication is successful, the login function is used to log the user in.

This code is vulnerable to concurrent sessions for a couple of reasons:

1. No session limit: There is no check to limit the number of active sessions a user can have. This means that a user can log in from multiple devices or locations at the same time. This can lead to unauthorized access if a user's credentials are compromised.

2. No notification for concurrent sessions: The code does not have any mechanism to inform the user when a session has already been initiated or when a new session starts from a different location. This lack of notification means that users may be unaware when their account is accessed from a different location, making it harder to detect and respond to unauthorized access.

In order to fix these vulnerabilities, the code needs to be modified to limit the number of active sessions per user and notify users of concurrent sessions. This could be achieved by keeping track of active sessions for each user and checking this before allowing a new session to start. Additionally, a notification system could be implemented to alert users of new sessions.

Steps

  • Implement a session management system that tracks active sessions for each user.
  • Before authenticating a user, check if there is already an active session for that user.
  • If an active session exists, decide on a policy: either deny the new login attempt, or invalidate the old session and create a new one.
  • Consider notifying the user when a new session is initiated, especially if it's from a different location. This can be done via email or an in-app notification.
  • Implement a mechanism to automatically log out inactive sessions after a certain period of time to prevent session hijacking.

Compliant code

        from django.contrib.auth import authenticate, login, logout
from django.contrib.sessions.models import Session
from django.core.mail import send_mail
from django.http import HttpResponse

def login_view(request):
    # Get the username and password from the POST request
    username = request.POST['username']
    password = request.POST['password']
    
    # Authenticate the user
    user = authenticate(request, username=username, password=password)
    
    # If the user is authenticated successfully
    if user is not None:
        # Check if there is already an active session for this user
        sessions = Session.objects.filter(expire_date__gte=timezone.now(), session_key=request.session.session_key)
        if sessions.exists():
            # If an active session exists, invalidate the old session
            logout(request)
            # Notify the user about the new session
            send_mail(
                'New session initiated',
                'A new session has been initiated for your account.',
                'from@example.com',
                [user.email],
                fail_silently=False,
            )
        # Login the user
        login(request, user)
        return HttpResponse("You are now logged in.")
    else:
        return HttpResponse("Invalid username or password.")
        
        

The updated code now includes a session management system that tracks active sessions for each user. Before authenticating a user, it checks if there is already an active session for that user. If an active session exists, it invalidates the old session and logs the user out.

The user is then notified about the new session via an email. This is especially useful if the session is initiated from a different location, as it could be a sign of a potential security threat.

The login_view function now also uses Django's logout function to log out the user from the old session before logging them into the new one. This helps prevent session hijacking by ensuring that there is only one active session per user at any given time.

Finally, the Session model is used to automatically log out inactive sessions after a certain period of time. This is done by filtering out sessions that have an expire_date greater than or equal to the current time.

References