Securing Django Views from Unauthorized Access

Protecting your database from unauthorized access is extremely important to protect not only your website but your users personal information and content too. There are several ways to help minimize the risk of someone brute forcing their way into a view to edit or obtain data.

The first thing we can do is on the front end and this would be to hide the links that access that page. This can be done very easily with django templating.

Using an if statement, we can check if the request.user is the owner of the object, so in this case, is the recipe.owner who created the object:

{ % if request.user == recipe.owner % }
<div class="text-center">
     <a href="{ % url 'edit_recipe' recipe.id % }" class="btn btn-primary w-25">Edit</a>
     <a href="{ % url 'delete_recipe' recipe.id % }" class="btn btn-primary w-25">Delete</a>
</div>
{ % endblock % }

While this is a good first step, it still does not fully secure the view and prevent unwanted access. If a user was able to figure out the URL pattern of the view, they could quite simply change it and end up being able to edit another users recipe post. If they had their own recipe and hit edit, they would be able to see the URL pattern which could be something like:

https://www.mysuperawesomerecipe.com/recipe/edit/5/

If the user changes the 5 for another number, this would then open up the edit page for another users recipe providing the ID is valid.

How do we combat this? We secure it from the view as well by doing checks before allowing the content to load. For class Based views this can be done with UserPassesTestMixin.

from django.contrib.auth.mixins import UserPassesTestMixin

After we import the mixin, we can add it as a parameter into the class:

class EditRecipe(UserPassesTestMixin, UpdateView):

The next step we must do is create our test_func(), this class method will return a True or False value. Example code:

def test_func(self):
    return self.request.user == self.get_object().owner

This code is getting the user who is making a request to the page and then checking if that user is the objects 'owner'. Owner being the model field connected to the user in the recipe model.

If it returns False, it will throw a 403 error, which we can handle with a custom error page. If it returns True, it will proceed to the edit page and allow the user to update their record.

Alternatively this can be done in a functional view or within another class method with an if statement and a redirect:

recipe = Recipe.objects.get(id=id)

if not recipe.owner == request.user:
   messages.error(
        request, 
        'Error, you are unauthorised to edit this recipe'
)
   return redirect(reverse('recipes'))
else:
...
Edit code here
...

Now only the owner of that recipe will be able to edit it!

CodingSecurityDjango
Avatar for Daisy McGirr

Written by Daisy McGirr

Software Engineer & Student Mentor

Loading

Fetching comments

Hey! 👋

Got something to say?

or to leave a comment.