HIGH cross site request forgerydjango

Cross Site Request Forgery in Django

How Cross Site Request Forgery Manifests in Django

Cross Site Request Forgery (CSRF) in Django occurs when an attacker tricks an authenticated user into submitting a malicious request without their knowledge. In Django applications, this typically manifests through state-changing operations like POST, PUT, DELETE requests that lack proper CSRF protection.

The most common Django CSRF vulnerability appears in form submissions. Consider this vulnerable view:

from django.shortcuts import render, redirect
from django.http import HttpResponse

def vulnerable_view(request):
    if request.method == 'POST':
        # Process form data without CSRF check
        user = request.user
        user.email = request.POST['email']
        user.save()
        return redirect('profile')
    return render(request, 'form.html')

An attacker can create a malicious page that submits this form automatically:

<form action="https://yourdjangoapp.com/profile/update" method="POST" id="csrf-form" style="display:none;">
    <input type="hidden" name="email" value="attacker@example.com">
</form>
<script>
    document.getElementById('csrf-form').submit();
</script>

When an authenticated user visits this malicious page, their browser automatically includes their session cookie, allowing the attacker to change their email without consent.

Django's @csrf_protect decorator and {% csrf_token %} template tag prevent this by requiring a unique token that attackers cannot forge. Without these protections, any authenticated POST request becomes vulnerable.

Django-Specific Detection

Detecting CSRF vulnerabilities in Django requires examining both code patterns and runtime behavior. middleBrick's Django-specific scanning identifies CSRF issues through several methods:

Code Analysis - middleBrick analyzes your Django templates and views for missing CSRF tokens. It flags forms that lack {% csrf_token %} in POST forms and views decorated with @csrf_exempt or missing @csrf_protect.

Runtime Testing - The scanner sends POST requests without CSRF tokens to test if the application accepts them. Django's CsrfViewMiddleware should reject these requests with HTTP 403 Forbidden, but misconfigurations can allow them through.

Middleware Configuration - middleBrick checks your MIDDLEWARE settings for proper CsrfViewMiddleware ordering. The middleware must be placed after SessionMiddleware and AuthenticationMiddleware to function correctly.

Decorator Usage - The scanner identifies @csrf_exempt usage throughout your codebase, flagging potentially dangerous exemptions. It also checks for proper @csrf_protect usage on state-changing views.

CSRF Cookie Settings - middleBrick verifies your CSRF_COOKIE settings, checking for secure cookie configurations and proper SameSite attributes.

Using middleBrick's CLI for Django CSRF detection:

npx middlebrick scan https://yourdjangoapp.com --output=json

The scanner reports findings with severity levels and specific line numbers where CSRF protections are missing, helping developers quickly locate and fix vulnerabilities.

Django-Specific Remediation

Remediating CSRF vulnerabilities in Django involves implementing proper protections at both the template and view levels. Here's how to secure your Django application:

Template Protection - Always include {% csrf_token %} in POST forms:

<form method="post" action="{% url 'update_profile' %}">
    {% csrf_token %}
    <input type="email" name="email" required>
    <button type="submit">Update</button>
</form>

View Protection - Use @csrf_protect decorator on state-changing views:

from django.views.decorators.csrf import csrf_protect

@csrf_protect
def update_profile(request):
    if request.method == 'POST':
        form = ProfileForm(request.POST)
        if form.is_valid():
            form.save()
            return redirect('profile')
    else:
        form = ProfileForm()
    return render(request, 'update.html', {'form': form})

Class-Based Views - For CBVs, use the csrf_protect mixin or ensure middleware handles protection:

from django.views.generic.edit import UpdateView
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_protect

@method_decorator(csrf_protect, name='dispatch')
class ProfileUpdateView(UpdateView):
    model = UserProfile
    fields = ['email', 'name']
    template_name = 'update.html'

API Endpoints - For AJAX requests, ensure CSRF tokens are included in headers:

// In your template
{% csrf_token %}
<script>
    var csrftoken = document.querySelector('[name=csrfmiddlewaretoken]').value;
    
    fetch('/api/profile', {
        method: 'POST',
        headers: {
            'X-CSRFToken': csrftoken,
            'Content-Type': 'application/json',
        },
        body: JSON.stringify({email: 'new@example.com'})
    });
</script>

Middleware Configuration - Ensure proper middleware ordering in settings.py:

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    # ... other middleware
]

Testing Protection - Use Django's test client to verify CSRF protection:

from django.test import TestCase, Client
from django.urls import reverse

class CsrfTest(TestCase):
    def test_csrf_protection(self):
        client = Client()
        response = client.post(reverse('update_profile'), {
            'email': 'test@example.com'
        })
        self.assertEqual(response.status_code, 403)  # Should be forbidden without CSRF token

Frequently Asked Questions

Why does Django's @csrf_exempt decorator exist if it's dangerous?
The @csrf_exempt decorator exists for specific use cases where CSRF protection isn't needed, such as public APIs that don't modify state, GET endpoints that only retrieve data, or when using token-based authentication instead of session cookies. However, it should never be used on POST/PUT/DELETE endpoints that modify user data.
How does middleBrick detect CSRF vulnerabilities in Django applications?
middleBrick detects Django CSRF vulnerabilities through multiple methods: it analyzes your source code for missing {% csrf_token %} tags and @csrf_exempt decorators, sends test requests without CSRF tokens to verify if they're accepted, checks middleware configuration for proper CsrfViewMiddleware ordering, and examines CSRF cookie settings for secure configurations.