Insecure session management - Change Password - Python

Insecure session management - Change Password - Python

Need

Secure session management after password change

Context

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

Description

Non compliant code

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

def change_password(request):
    if request.method == 'POST':
        form = PasswordChangeForm(request.user, request.POST)
        if form.is_valid():
            user = form.save()
            update_session_auth_hash(request, user)  # This line keeps the user logged in
            messages.success(request, 'Your password was successfully updated!')
            return redirect('change_password')
        else:
            messages.error(request, 'Please correct the error below.')
    else:
        form = PasswordChangeForm(request.user)
    return render(request, 'change_password.html', {'form': form})
        
        

The above code is a Django view function for changing a user's password. The function checks if the request method is POST, which means the form is being submitted. It then checks if the form is valid. If the form is valid, it saves the new password for the user and updates the session hash. The update_session_auth_hash() function is called to keep the user logged in after their password is changed.

The vulnerability lies in the fact that the session remains open even after the password is changed. This means that if an attacker has gained access to the user's session, they can continue to use it even after the user has changed their password. The session should be invalidated after a password change to prevent this.

Steps

  • Remove the line of code that updates the session hash after the password change. This line is keeping the user logged in even after the password change.
  • After the password change, invalidate the current session and create a new one. This can be done by logging the user out and then logging them back in with the new password.
  • Ensure that the new session ID is not predictable. It should be randomly generated and not based on user information or the previous session ID.
  • After the session has been invalidated and a new one created, redirect the user to the login page. This forces the user to log in again with their new password, ensuring that the session is secure.

Compliant code

        from django.contrib.auth import authenticate, login, logout, update_session_auth_hash
from django.contrib.auth.forms import PasswordChangeForm
from django.contrib import messages
from django.shortcuts import render, redirect

def change_password(request):
    if request.method == 'POST':
        form = PasswordChangeForm(request.user, request.POST)
        if form.is_valid():
            user = form.save()
            # Invalidate the current session
            logout(request)
            # Authenticate the user with new password
            new_password = form.cleaned_data.get('new_password1')
            user = authenticate(username=user.username, password=new_password)
            # Create a new session
            if user is not None:
                login(request, user)
            messages.success(request, 'Your password was successfully updated! Please log in again.')
            return redirect('login')
        else:
            messages.error(request, 'Please correct the error below.')
    else:
        form = PasswordChangeForm(request.user)
    return render(request, 'change_password.html', {'form': form})
        
        

The updated code now includes a process to invalidate the current session and create a new one after a password change. This is done by calling the logout(request) function immediately after the password is changed. This function logs the user out and invalidates the current session.

Next, the user is authenticated with their new password using the authenticate(username=user.username, password=new_password) function. If the user is authenticated successfully, a new session is created by calling the login(request, user) function.

Finally, the user is redirected to the login page with a success message indicating that their password was successfully updated and they need to log in again. This ensures that the user is aware that they have been logged out and need to log in again with their new password.

This process ensures that the session is secure after a password change, as the old session is invalidated and a new one is created. The new session ID is not predictable as it is randomly generated by Django.

References