I'm creating multiple Django apps with vote possibilities, so I made an appvote to handle all this votes. In my templates I'm including an ajax-function namedvote. To know on which model I'm liking I addapp_name andmodel_name to thevote function (I made some templatetags to get these values). In my views.py I usemodel = apps.get_model(app_name, model_name) to get the model class. But now I'm worried a hacker could do something with theapp_name andmodel_name values.
vote/ajax.html (only function):
function vote(bool){ $.ajax({ type: "post", timeout: 8000, url: '{% url 'ajax:vote' %}', dataType: 'json', data: { 'csrfmiddlewaretoken': getCookie('csrftoken'), 'model_name': "{{ model|get_model_name }}", 'app_name': "{{ model|get_app_name }}", 'voted': bool, 'id': "{{ model.id }}", }, success: function(data) { if (!data.error){ if (bool){ $(".half .fa-thumbs-up").removeClass("far").addClass("fas"); $(".half #count").text(parseInt($(".half #count").text()) + 1); } else { $(".half .fa-thumbs-down").removeClass("far").addClass("fas"); $(".half #count").text(parseInt($(".half #count").text()) - 1); } } } });}ajax/views.py:
def vote(request): try: app_name = request.POST.get("app_name") model_name = request.POST.get("model_name") id = request.POST.get("id") votedFor = True if request.POST.get("voted") == "true" else False except ValueError: return JsonResponse({"error": True}) model = apps.get_model(app_name, model_name) if model is None or id is None: return JsonResponse({"error": True}) try: usable_model = model.objects.get(id=id) except model.DoesNotExist: return JsonResponse({"error": True}) try: usable_model.vote._meta.get_field("votes") except FieldDoesNotExist: return JsonResponse({"error": True}) usable_model.vote.vote(request, votedFor) return JsonResponse({"error": False})vote/functions:
def vote(self, request, votedFor): if request.user.is_authenticated: if not UserVoted.objects.filter(User=request.user, Vote=self).exists(): UserVoted.objects.create(User=request.user, Vote=self, votedFor=votedFor) self._like_or_dislike(votedFor) return True return False ip = get_client_ip(request) if ip: if not UserVoted.objects.filter(ip=ip, Vote=self).exists(): UserVoted.objects.create(ip=ip, Vote=self, votedFor=votedFor) self._like_or_dislike(votedFor) return True return False return Falsedef _like_or_dislike(self, votedFor): if votedFor is not None: Vote.objects.filter(id=self.id).update(votes=F('votes') + 1) if votedFor else Vote.objects.filter(id=self.id).update(votes=F('votes') - 1) return True return FalseI already manipulatedapp_name andmodel_name and the server didn't crash but I don't know what a hacker can do. Can he crash my server when he manipulate these values? (maybe "ajax-injection" or something like this?)
- 5\$\begingroup\$Your indentation is off. This being Python, indentation is very important. Remove your code, paste it in file-by-file and with every bit you paste in, select it, hit Ctrl + K. The question editor should do the rest.\$\endgroup\$2019-01-22 21:21:27 +00:00CommentedJan 22, 2019 at 21:21
1 Answer1
Question
But now I'm worried a hacker could do something with the
app_nameandmodel_namevalues.Can he crash my server when he manipulate these values? (maybe "ajax-injection" or something like this?)
I'm not sure what the best approach to this would be. Perhaps it would be wise to define a list of the values that are acceptable for a user to pass there, though maybe that wouldn't be sufficient.
Other review points
function vote(bool){
The namebool is not very descriptive. Given that it is used as the value for thevoted parameter a name likevoted would be more appropriate. And if your code complies withecmascript-6 standards you could simply write voted
in the list of parameters as a shorthand forvoted: voted
The success handler looks like this:
success: function(data) { if (!data.error){ if (bool){ $(".half .fa-thumbs-up").removeClass("far").addClass("fas"); $(".half #count").text(parseInt($(".half #count").text()) + 1); } else { $(".half .fa-thumbs-down").removeClass("far").addClass("fas"); $(".half #count").text(parseInt($(".half #count").text()) - 1); }
There is quite a bit of redundancy in both cases. AlsoparseInt() calls should pass a radix1.
if (!data.error){ const thumbClass = '.fa-thumbs-' + bool ? 'up' : 'down'; $(".half " + thumbClass).removeClass("far").addClass("fas"); const toAdd = bool ? 1 : -1; $(".half #count").text(parseInt($(".half #count").text(), 10) + toAdd);In thevote function in ajax/views.py there is this line:
votedFor = True if request.GET.get("voted") == "true" else False
This could be simplified to just:
votedFor = request.GET.get("voted") == "true"- 1\$\begingroup\$Wow thank you for your answer for my old question, that isn`t very common! I already found a better way. I register all models in a global dict by saving the model class with a random ID. In the frontend then I use the ID and send it, in the backend I then can easily get the model by the ID.\$\endgroup\$Myzel394– Myzel3942020-04-09 20:21:07 +00:00CommentedApr 9, 2020 at 20:21
You mustlog in to answer this question.
Explore related questions
See similar questions with these tags.

