Getting Past Django CSRF Middleware With Ajax

Django’s Cross Site Request Forgery protection is an important security measure to prevent malicious requests from other sites. However, it can cause frustrating errors when sending legitimate requests, especially Ajax POST requests. In this post, we’ll examine why you may encounter 403 CSRF failures with Ajax and how to properly configure Django and your JavaScript to bypass the checks.

Why CSRF Check Fails for Ajax Requests

Django looks for a valid CSRF token to verify each POST request. This unique token is added to forms in a hidden input. When submitted through Django’s normal request/form handling, everything works smoothly.

However, an Ajax POST sends data separately without the related CSRF token. As a result, Django will reject the request due to lack of proper verification. Although irritating, this protection blocks unauthorized data saves or deletions by malicious sites impersonating a user.

First Try: Fetch CSRF Token in JavaScript

To bypassCSRF protection, each Ajax call must send back the token. A common approach tries fetching the token value via JavaScript. However, this opens up potential security issues if the JavaScript is manipulated.

Instead of relying solely on client-side JavaScript for security, the recommended method is configuring Django and your Ajax handler properly to share tokens safely.

Rather than tack on CSRF handing in each JavaScript call, it’s cleaner to enable token access globally. By tweaking Django’s middleware settings, your Ajax frontend can reliably obtain fresh tokens with each request.

First, adjust the CsrfViewMiddleware configuration under MIDDLEWARE to expose the token.

MIDDLEWARE = [
    ...
    'django.middleware.csrf.CsrfViewMiddleware',
    ...
]  

CSRF_COOKIE_HTTPONLY = False

With HTTP only disabled, JavaScript can now read the CSRF token cookie. Next we’ll set up Ajax to send this token automatically.

Complete Ajax POST Request with Token

jQuery supplies a convenient helper to add CSRF tokens to all Ajax requests. Once configured, any POSTs handle tokens without any extra code.

function getCookie(name) {
    let cookieValue = null;
    if (document.cookie && document.cookie !== '') {
        const cookies = document.cookie.split(';');
        for (let i = 0; i < cookies.length; i++) {
            const cookie = cookies[i].trim();
            // Does this cookie string begin with the name we want?
            if (cookie.substring(0, name.length + 1) === (name + '=')) {
                cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                break;
            }
        }
    }
    return cookieValue;
}

$.ajaxSetup({
    beforeSend: function(xhr, settings) {
        if (!(/^http:.*/.test(settings.url) || /^https:.*/.test(settings.url))) {
            // Only send the token to relative URLs i.e. locally.
            xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
        }
    }  
});

Now Ajax will automatically fetch the current CSRF token value and pass it in the request headers. With configuration complete, Django will properly validate POST requests from our JavaScript code.

Summary: Securing Ajax Requests

Django‘s CSRF protection causes Ajax POST requests to fail validation until properly handled. After making sure middleware is configured to allow reading the token cookie, jQuery can automatically apply it without any extra code. Following these steps secures your application while eliminating frustrating 403 errors.

Proper CSRF configuration aids the Frontend and Backend communication along with security. With tokens passed along requests automatically, you can focus on building features instead of fighting errors!