Django Rest framework how to apply restriction on public api for unauthenticated users?

I have an contact forms api for unauthenticated user. I integrated my api in reactjs. So anyone can visit my website and submit forms. But anyone can view the json data if he directly visit the api url. Anyone can also submit post request using POSTMAN by api url. How to restrict anyone to view the api page and also prevent unauthorized post request.

here is my code:

settings.py:

REST_FRAMEWORK = {
    # Only enable JSON renderer by default.
    'DEFAULT_RENDERER_CLASSES': [
        'rest_framework.renderers.JSONRenderer',
    ],
    'DEFAULT_THROTTLE_CLASSES': [
        'rest_framework.throttling.AnonRateThrottle',

    ],
    'DEFAULT_THROTTLE_RATES': {
        'anon': '10/minute',

    }
}  

views.py

api_view(['POST', 'GET'])
def my_api(request):
    if request.method == 'POST':
        data = request.data
        serializer = ContactSerializer(data=data)
        if serializer.is_valid():
            serializer.save()
            print(serializer.data)
            return Response({
                'status': True,
                'message': 'sucess'
            })

        return Response({
            'status': False,
            'message': serializer.errors

        })
    if request.method == "GET":
        contact = Contact.objects.all()
        serializer = ContactSerializer(contact, many=True)
        return Response(serializer.data)

I used AnonRateThrottle but still now anyone can submit POST request using the api url. How to prevent it? Basically I want to allow post request if it’s actually come from my website and also how to restrict access view api page?

Your options are documented on the DRF web site. See Authentication - Django REST framework to get started.

I’m not sure what you’re looking for here - generally speaking the POST comes from the browser, not your site - unless you’ve got a view that is calling another view using the API.

1 Like

KenWhitesell POST comes from the browser, not your site - then what happen if I have an public api for unauthenticated users for submit contact forms data or like this. If anybody can get the api url then he can sent post request which one kind of security risk. I want to only allow or accept post request if it’s come from my website.

I read the doc but didn’t find how to accept post request form any specific website or ip address. I also set my domain name in CORS_ALLOWED_ORIGINS but still now I can sent post request using any third party app like “POST MAN”.

see my updated code where only admin user approved for get request but as I am using post request for unauthenticated user so I am not understanding how to allow post request only from my domain.

if request.method == 'POST':
        data = request.data
        serializer = ContactSerializer(data=data)
        if serializer.is_valid():
            serializer.save()
            print(serializer.data)
            return Response({
                'status': True,
                'message': 'sucess',
            })

        return Response({
            'status': False,
            'message': serializer.errors,
            

        })
        
        
   
    if request.method == "GET":
        if request.user.is_superuser:
            contact = Contact.objects.all()
            serializer = ContactSerializer(contact, many=True)
            return Response(serializer.data)
        else:
            return Response(" ")

But anyone can send post requests in an unauthenticated situation.

Allowing for an unauthenticated POST is the security risk, not the source of the POST.

Correct. You have no way - repeat, no, absolutely none - to prevent a POST submission to an API.

I am thinking to add google recaptcha as mandatory in my api request. So any post request will not accepted until get successful recaptcha response.

Integrating google recaptcha is the only solution for prevent unauthorized post request from unauthenticated users.

Sorry, that doesn’t prevent anything. If I wanted to post malicious data, I would create my own fake page from the form I get from your site and alter it to submit whatever data I want.

1 Like

KenWhitesell didn’t you think it’s an security risk? Sometimes we need to receive data from unauthenticated users and what will be your suggestion for prevent or minimize risk for this type of situation where we are using public api for unauthenticated user.

I don’t work in an environment where it’s desirable to accept API input from unauthenticated users. In fact, I can’t envision a situation where it’s wise to do so under any circumstance.

The appropriate way to mitigate the risk is to not allow unauthenticated submissions.

[Edit: This is not including cases where input and values can be carefully filtered and verified - such as a shopping-cart type situation. That’s a different and much more restricted environment that by its nature is resistent to malicious submissions.]

1 Like

KenWhitesell I have an question about TokenAuthentication. I want to use somethings like this in my frontend for getting requests from unauthenticated user. Actually now post request not coming from unauthenticated user. I will create an user then pass his token in header when post request will be coming:

 const res = await axios.post(url,{
          contact_name:contact_name,contact_email:contact_email,contact_body:contact_body
        },
      'header':{
       { 'authorization': `Token ${token}`},
}
)

Now my questing if you go to my website and submit contact forms data then can you see the authorization token when post request will be sending? is it safe now?

KenWhitesell ???

Always keep these fundamental principles in mind:

  • The browser is not secure

  • There is nothing you can do to secure a browser

  • You have no control over the browser

  • Whatever security exists in the browser exists to protect the browser and the computer it’s running on, not the server being accessed.

  • You cannot hide data in the browser

  • You cannot prevent a person from running a patched browser that exposes all data being sent to it

  • The browser is never “safe” or “secure”.

  • You must always validate data being submitted to your site

  • You must never trust the browser to be sending you valid data

  • You must never assume that data submitted is coming from a trusted source

Authentication, by definition means that you know who is making the request. Authentication, by itself, does not make your site secure - it simply lets you know who has taken action you may consider malicious, and gives you a way to prevent further malicious activity by that user.

Simply assigning a “User” to a request is not authentication.

These are fundamentals in that it doesn’t matter what you’re running on the server. It doesn’t matter what language your system is written in or what framework you are using. This isn’t specific to Python or Django.

You cannot trust the browser.

1 Like