WATCH FULL VIDEO BELOW
Tech

Understanding Django CSRF Tokens: What They Are and Why You Need Them

Django is a Python web framework you can use to build secure web applications. It offers many features to help developers with security. One of these features is CSRF tokens, essential in protecting forms from Cross-Site Request Forgery attacks.


What Is a CSRF Token?

A CSRF token is a security feature that protects web applications from Cross-Site Request Forgery (CSRF) attacks. It allows the application server to check whether a form submission came from an authentic browser or a hacker forged it.

MAKEUSEOF VIDEO OF THE DAYSCROLL TO CONTINUE WITH CONTENT

CSRF tokens are form inputs that keep track of a user session. A website’s server-side web application framework typically generates CSRF tokens for each unique user session. The server checks if the token is correct whenever a user submits a form. CSRF tokens generally consist of random strings and numbers, making their values unpredictable.

CSRF Token Generation in Django

Django’s get_token() function randomly generates CSRF tokens. To find this function, navigate to the csrf.py file inside your Python virtual environment. The folder structure should look like this:

 env/

└── Lib/

    └── site-packages/

        └── django/

            └── middleware/

                └── csrf.py

Inside this file, you will find the get_token() function, which returns the token. Django uses data masking to protect the token’s value from hackers.

By default, Django enables CSRF protection for your site by adding django.middleware.csrf.CsrfViewMiddleware in the MIDDLEWARE list of your settings.py file. All you need to do is add {% csrf_token %} to your POST forms. Without adding {% csrf_token %}, you will get a 403 (forbidden) error when you submit a form.

Django's 403 forbidden error page in development mode

When you add {% csrf_token %} to your form, it automatically creates a hidden input field with the name csrfmiddlewaretoken, which contains the value of the masked CSRF token. The server uses this value to determine whether the form submission is authentic. You can check the value of this hidden field by viewing the page source or using your browser’s developer tools feature.

csrf token hidden input field added by django

How CSRF Tokens Work in Django

When you launch your site with the form, Django automatically creates a browser cookie called csrftoken. This cookie keeps track of user activity on the site and uniquely identifies each user.

When the user submits the form, the server compares the value of the cookie to the value of the csrfmiddlewaretoken in the hidden input field. If these values match, the server will process the form successfully, otherwise it will produce an error.

At first glance, the values of the cookie and the csrfmiddlewaretoken appear to be different. This is intentional and adds an extra layer of protection to the CSRF token. The CSRF token gets compared to the cookie like this:

  • The get_token() function masks the CSRF token before passing it on to the input field.
  • When the form submits, the CSRF token gets unmasked with the help of the secret key in the settings file.
  • The unmasked token gets compared to the session cookie.
  • If the values are the same, the form gets processed. If not, the server returns an error.

To prevent hackers from stealing your CSRF token, Django renews it each time it starts a user session.

the csrf cookie stored in the browser's storage

Creating Custom CSRF Tokens

Although Django makes it easy to protect your forms by simply adding the {% csrf_token %}, generating CSRF tokens and manually adding them to your forms is also possible. To do this, import the get_token() function:

 from django.middleware.csrf import get_token

In your view, you can generate the CSRF token like this:

 def view_name(request):
    csrf_token = get_token(request)

    
    context = {
        "csrf_token": csrf_token
    }

    return render(request, 'app_name/template.html', context=context)

In your HTML template, you can manually include your input tag and add the csrf_token to it like this:

 <form method="POST" >
    <input type="hidden" name="csrfmiddlewaretoken" value="{{ csrf_token }}">
    {{form.as_p}}
    <button type="submit" class="btn btn-outline-secondary">Add Bookbutton>
form>

Alternatively, you can generate the hidden input field from your views like this:

 def your_view(request):
    csrf_token = get_token(request)
    csrf_token_html = ''.format(csrf_token)

    
    context = {
        "csrf_token": csrf_token_html
    }

    return render(request, 'app_name/template.html', context=context)

You can then add it to your HTML template like this:

 <form method="POST" >
    {{ csrf_token_html|safe }}
    {{form.as_p}}
    <button type="submit" class="btn btn-outline-secondary">Add Bookbutton>
form>

If you want to completely control your form’s CSRF protection, you can do that by comparing your CSRF token to the cookie stored in the browser. Based on the results of the comparison, you can handle the form submission however you want. Here’s an example:

 from django.shortcuts import render
from django.middleware.csrf import get_token, _unmask_cipher_token
from django.utils.crypto import constant_time_compare

def your_view(request):
    
    csrf_token = get_token(request)
    csrf_cookie = request.COOKIES.get('csrftoken')

    
    unmasked_csrf_token = _unmask_cipher_token(csrf_token)
    
    
    if not constant_time_compare(unmasked_csrf_token, csrf_cookie):
        
        pass
    else:
        
        pass
        
    
    context = {
        'csrf_token': csrf_token,
    }

    return render(request, 'app_name/template.html', context=context)

This code snippet retrieves the csrf_cookie from the HTTP request object. It then uses the _unmask_cipher_token() function to unmask the csrf_token.

A conditional statement compares the values of the retrieved csrf_cookie and the unmasked csrf_token. This comparison uses the constant_time_compare function to protect against timing exploits. You can write your logic based on the result of the comparison.

Disabling CSRF Protection in Django

Even though Django makes a default provision for CSRF protection, you can disable it in your project if you want. There are two ways to do this:

  • Disabling CSRF protection on your entire website.
  • Disabling CSRF protection on a specific view.

Disabling CSRF Protection on Your Entire Website

To disable Django’s CSRF protection on your website, you simply have to remove the CSRF middleware from your settings file. In your settings file, locate a list called MIDDLEWARE. Inside the list, search for this:

 'django.middleware.csrf.CsrfViewMiddleware',

Once you find it, you should remove it from your code for Django’s default CSRF protection to disable it.

Disabling CSRF Protection on a Specific View

If you only want to disable CSRF protection on a specific Django view, use the @csrf_exempt decorator. Here’s a code snippet to demonstrate:

 from django.views.decorators.csrf import csrf_exempt

@csrf_exempt
def view_name(request):
    
    pass

The @csrf_exempt decorator is just one of several related to CSRF protection in Django. You can read about the rest on Django’s CSRF reference.

Do Not Disable CSRF Protection on Your Website

Although Django makes it possible, disabling Django’s built-in CSRF protection mechanism is not recommended. Doing so will make your site vulnerable to CSRF attacks and ultimately affect the users of your app negatively.

Unless you are an experienced developer who knows how to implement a custom CSRF protection mechanism, you should work with the alternative provided by Django.

Muhabarishaji

🧪 |Medical Laboratory Scientist 🥇 | Mindset over Everything. 
 🤝 | Let's Grow Together.

Related Articles

Back to top button