Insecure object reference - User deletion - Python

Insecure object reference - User deletion - Python

Need

Secure user deletion and session management

Context

  • Usage of Python 3 for writing and executing Python code
  • Usage of Django for building web applications in Python

Description

Non compliant code

        from django.contrib.auth.models import User
from django.http import HttpResponse
from django.views import View

class DeleteUserView(View):
    def get(self, request, *args, **kwargs):
        user_id = request.GET.get('id')
        User.objects.filter(id=user_id).delete()
        return HttpResponse("User deleted")
        
        

This code shows a Django view that allows any user to delete any other user, just by knowing their ID. The problem lies in the fact that there is no check to verify if the user requesting the deletion has the necessary permissions.

In the get method of DeleteUserView, we retrieve the id from the GET parameters of the request. We then use this id to filter the User model and delete the user with that id. The deletion of a user is a critical operation and should be protected.

Moreover, after the deletion of the user, the user's session is not deleted, which allows the user to continue browsing the application. This is a security issue as it allows for potential unauthorized access to the application after the user's account has been deleted.

To fix this vulnerability, we should only allow authorized users to delete users and we should also delete the user's session after their account has been deleted.

Steps

  • Validate the user's permissions before deleting. Only authorized users (like admins) should be able to delete users.
  • Use POST method instead of GET for deleting users. GET requests should be idempotent and safe, which means they should not change the state of the server. Deleting a user is a state-changing operation and should be done via POST or DELETE HTTP methods.
  • Implement proper error handling. If the user does not exist or an error occurs during deletion, the application should handle this gracefully and inform the user.
  • After deleting a user, invalidate their session. This prevents the deleted user from continuing to interact with the system.
  • Consider using Django's built-in views for user management. These views already have many security features implemented.

Compliant code

        from django.contrib.auth.decorators import login_required, user_passes_test
from django.contrib.auth.models import User
from django.contrib.sessions.models import Session
from django.http import HttpResponse, JsonResponse
from django.views import View
from django.views.decorators.csrf import csrf_protect
from django.shortcuts import get_object_or_404

class DeleteUserView(View):
    @csrf_protect
    @login_required
    @user_passes_test(lambda u: u.is_superuser)
    def post(self, request, *args, **kwargs):
        user_id = request.POST.get('id')
        user = get_object_or_404(User, id=user_id)
        user.delete()

        # Invalidate all sessions for this user
        [s.delete() for s in Session.objects.filter(expire_date__gte=timezone.now(), session_key=user.session_key)]

        return JsonResponse({"message": "User deleted successfully"})

        
        

The updated code now includes several security measures to prevent insecure object reference vulnerabilities:

1. User Permissions: The @user_passes_test(lambda u: u.is_superuser) decorator is used to ensure that only superusers (like admins) can delete users. This prevents unauthorized users from deleting users.

2. HTTP Method: The post method is used instead of get for deleting users. This is because GET requests should be idempotent and safe, meaning they should not change the state of the server. Deleting a user is a state-changing operation and should be done via POST or DELETE HTTP methods.

3. Error Handling: The get_object_or_404(User, id=user_id) function is used to handle cases where the user does not exist. If the user does not exist, a 404 error will be returned.

4. Session Invalidation: After a user is deleted, all their sessions are invalidated. This is done by deleting all sessions for the user from the Session model. This prevents the deleted user from continuing to interact with the system.

5. CSRF Protection: The @csrf_protect decorator is used to protect against cross-site request forgery attacks. This is a type of malicious exploit where unauthorized commands are transmitted from a user that the web application trusts.

6. Login Required: The @login_required decorator ensures that the user is logged in before they can delete users. This is another layer of security to prevent unauthorized access.

7. Response: A JSON response is returned instead of a simple string. This is a more standard way of returning responses from an API.

References