How to prevent user from modifying data through Django DRF
My API endpoints are exposed to the browser via Django DRF which I'm aware is normal. However, the primary issue with this is that someone can perform any operation my API can perform without going through my application. I have validation for my endpoints but the user could delete payment records, for example, or POST invalid data, and other similar operations. I am using JWT auth but if the user is already logged in my application in the same browser they can see it. Is there any way to prevent this?
Set a custom header in all your frontend API requests (e.g., X-From-Frontend: true) and verify it on the backend. Write a custom middleware to verify the header.
In Frontend,
fetch("/api/endpoint", {
headers: {
"Authorization": "Bearer <token>",
"X-From-Frontend": "true"
}
})
In Dajngo,
class FrontendHeaderRequiredMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
if request.path.startswith("/api/") and request.method in ["POST", "PUT", "DELETE"]:
if request.headers.get("X-From-Frontend") != "true":
return JsonResponse({"detail": "Forbidden: Invalid source."}, status=403)
return self.get_response(request)
this will set the X-From-Frontend header in the frontend and the verifies it in django custom middleware.
this way you can only allow the requests from your frontend to access your apis
Firstly, I advise you to specify the authorized operations in each API (Post, Get, ...).
Also, I propose implementing a new header unique to you that you can store in your database, and this for each of your applications or interfaces. Then, implement a middleware that verifies that the requests come exactly from the interfaces you have in your database.
from django.db import models
import uuid
class AuthorizedInterface(models.Model):
name = models.CharField()
unique_identifier = models.UUIDField(default=uuid.uuid4, editable=False, unique=True, help_text="Unique identifier of the interface")
is_active = models.BooleanField(default=True, help_text="Indicates if this interface is active and authorized")
unique_identifier
it the value you can use a your hearder value.
for your middleware:
from django.utils.deprecation import MiddlewareMixin
from django.http import HttpResponseForbidden
from .models import AuthorizedInterface
class VerifyInterfaceOriginMiddleware(MiddlewareMixin):
def process_request(self, request):
origin_header = request.META.get('HTTP_X_INTERFACE_ID') # Custom header name
if not origin_header:
return HttpResponseForbidden("Missing origin header.")
try:
interface = AuthorizedInterface.objects.get(unique_identifier=origin_header, is_active=True)
request.authorized_interface = interface # Optional: store the interface in the request
return None
except AuthorizedInterface.DoesNotExist:
return HttpResponseForbidden("Request origin not authorized.")
and for your application, for example
fetch("/api/endpoint", {
headers: {
'Authorization': 'Bearer <token>',
'X-INTERFACE-ID': 'your-application-unique-id' // Replace with the actual ID
}
}
hope this can help you.
the primary issue with this is that someone can perform any operation my API can perform
You said yourself what is an issue. You need proper authorization and permission system.
Your users should be only allowed to perform specific operations.
You should never trust incoming data. Always run proper validation on the backend.
In my application we have user roles and permissions in place so for example:
- VIEWER can only use list and details endpoints
- EDITOR can also use update and create endpoints
etc
Check: https://www.django-rest-framework.org/api-guide/permissions/