After asking a question in stack overflow, by the way without finding an answer, but rather questions about why I did it this way, I saw that I was not the only one who had this approach.
So far no one has addressed this issue how to secure GET or POST requests in Django, AJAX, JS only that website can use it nobody else
Someone asked this question and this was my answer:
they always recommend "JWT, token authentication and session authentication", etc. But all those solutions require a user registered, and what happens if I want to protect a search autocomplete field or anything on the frontend that is public.
I have created a rest framework custom permission and I using django csrfmiddlewaretoken:
it behaves the same like Django post form, csrf token middleware send an input type hidden with
#{% csrf_token %}
(input hidden with the token) but and this case only needs
#{{ csrf_token }}
(the token), Django compares the request token with cookie token which are encrypted
permission.py
from django.middleware.csrf import _compare_salted_tokens, rotate_token
from rest_framework.permissions import BasePermission
class HasCsrfTokenValid(BasePermission):
def has_permission(self, request, view):
token_valid = False
try:
csrf_token = request.headers.get("api-csrftoken")
csrf_cookie = request.META.get("CSRF_COOKIE")
"""
Check if both alphanumerics(strings) values are differents to prevent
a malicious user get the csrf cookie and send it from the ajax.
"""
if csrf_token == csrf_cookie:
rotate_token(request)
return False
token_valid = _compare_salted_tokens(csrf_token, csrf_cookie)
except ValueError: # if csrf_token & csrf_cookie are not a valid alphanumeric
return False
return token_valid
add permission class to api view
#views.py
class SnippetSearchAPI(generics.ListAPIView):
model = Snippet
serializer_class = SnippetSearcSerializer
permission_classes = [HasCsrfTokenValid,]
queryset = Snippet.objects.all()
//Ajax request:
$('#search-snippet').keyup(function () {
$.ajax({
url:"{% url 'snippet-search-space:api' %}",
headers:{'api-csrftoken':'{{ csrf_token }}'},
success:function(data){
console.log(data)
}
});
});
conclusion:
So far I have solved it, but I don't know the security implications for the future, I tried it and it seems safe. but there will always be someone out there who can hack this, at least I think so.
what do you think?
Top comments (6)
I'm sorry for being dense, but I don't understand what problem this is solving.
Do you want to use the csrf token in a GET request?
See the following situation:
I have a public endpoint(API) to use only on my website, e.g. a search form with an autocomplete field, how to protect this field to not expose to the spammer. you would tell me to use JWT or authentication token (Well)
What if an anonymous user wants to search for something on my website?
Do I ask him to register?
How to use the token without exposing it in the frontend in the ajax request?
I know that I can use quota limitation(in fact I will use it)
but if in addition to that I want only my website can use this endpoint nobody else
How do I do it without exposing my token?
When I had the requirement of creating an API and "eating our own dog food", I made the backend call the API, rather than have it happen at the front end.
That way the API key is locked to one user, but many people can use it.
Ah! I see. Thank you for clarifying.
you are welcome
in Django 3.2: _compare_salted_tokens is not found in csrf