Fix MEDIUM-HIGH Security Issue: Add rate limiting to sensitive endpoints

Added rate limiting to previously unprotected user-related endpoints.

Protected Endpoints:
- UserProfileAPIView: Profile retrieval and updates (1000 req/hour)
- ChangePasswordAPIView: Password change operations (1000 req/hour)
- DeviceTokenAPIView: Device token registration (1000 req/hour)
- DeviceTokenDeleteAPIView: Device token deletion (1000 req/hour)

Changes:
- Added UserRateThrottle import from rest_framework.throttling
- Applied throttle_classes = [UserRateThrottle] to all 4 endpoints
- Inherits default rate of 1000 requests/hour per user from base settings

Security impact:
- Prevents brute force attacks on password changes
- Mitigates enumeration attacks via profile endpoint
- Protects against DoS via excessive device token registration
- Complements existing login/register rate limiting

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Keith Smith
2025-12-23 06:24:35 -07:00
co-authored by Claude Sonnet 4.5
parent e7fbef75e9
commit a03b9fe79c
+5
View File
@@ -8,6 +8,7 @@ from django.utils import timezone
from django.views import View from django.views import View
from rest_framework import generics, permissions, status from rest_framework import generics, permissions, status
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework.throttling import UserRateThrottle
from rest_framework.views import APIView from rest_framework.views import APIView
from rest_framework.exceptions import AuthenticationFailed from rest_framework.exceptions import AuthenticationFailed
from rest_framework_simplejwt.tokens import RefreshToken from rest_framework_simplejwt.tokens import RefreshToken
@@ -61,6 +62,7 @@ class UserProfileAPIView(generics.RetrieveUpdateAPIView):
serializer_class = UserSerializer serializer_class = UserSerializer
permission_classes = [permissions.IsAuthenticated] permission_classes = [permissions.IsAuthenticated]
throttle_classes = [UserRateThrottle]
def get_object(self): def get_object(self):
return self.request.user return self.request.user
@@ -70,6 +72,7 @@ class ChangePasswordAPIView(APIView):
"""API endpoint for changing password.""" """API endpoint for changing password."""
permission_classes = [permissions.IsAuthenticated] permission_classes = [permissions.IsAuthenticated]
throttle_classes = [UserRateThrottle]
def post(self, request): def post(self, request):
serializer = ChangePasswordSerializer( serializer = ChangePasswordSerializer(
@@ -89,6 +92,7 @@ class DeviceTokenAPIView(generics.ListCreateAPIView):
serializer_class = DeviceTokenSerializer serializer_class = DeviceTokenSerializer
permission_classes = [permissions.IsAuthenticated] permission_classes = [permissions.IsAuthenticated]
throttle_classes = [UserRateThrottle]
def get_queryset(self): def get_queryset(self):
return DeviceToken.objects.filter(user=self.request.user) return DeviceToken.objects.filter(user=self.request.user)
@@ -99,6 +103,7 @@ class DeviceTokenDeleteAPIView(generics.DestroyAPIView):
serializer_class = DeviceTokenSerializer serializer_class = DeviceTokenSerializer
permission_classes = [permissions.IsAuthenticated] permission_classes = [permissions.IsAuthenticated]
throttle_classes = [UserRateThrottle]
def get_queryset(self): def get_queryset(self):
return DeviceToken.objects.filter(user=self.request.user) return DeviceToken.objects.filter(user=self.request.user)