HIGH ssrfdjango

Ssrf in Django

How SSRF Manifests in Django

Server-Side Request Forgery (SSRF) in Django applications often exploits the framework's request handling and external service integration patterns. Django's flexibility with HTTP requests and template rendering creates multiple attack surfaces that malicious actors can leverage.

One common manifestation occurs in Django views that accept user-controlled URLs for external requests. Consider a Django view that proxies API calls:

from django.http import JsonResponse
import requests

def proxy_api(request):
    target_url = request.GET.get('url')
    response = requests.get(target_url)
    return JsonResponse(response.json())

This code is vulnerable because an attacker can supply internal network addresses like http://localhost:8000/admin/ or http://192.168.1.1, allowing them to probe internal services that should be inaccessible from the internet.

Django's template system can also be exploited for SSRF when using the {% include %} tag with user-supplied paths:

{% include request.GET.url %}

If the template engine's allowed_include_roots is not properly configured, this can lead to SSRF by including external URLs.

Another Django-specific SSRF vector appears in Django REST Framework (DRF) serializers that handle file uploads or external media:

from rest_framework import serializers

class MediaSerializer(serializers.Serializer):
    file_url = serializers.CharField()
    
    def validate_file_url(self, value):
        # Missing validation allows SSRF
        return value

Without proper validation, an attacker can supply internal network addresses to access services behind the firewall.

Django admin's AdminSite can also be a target when custom admin actions accept URLs. A vulnerable implementation might look like:

class CustomAdmin(admin.ModelAdmin):
    def import_data(self, request, queryset):
        url = request.POST.get('data_url')
        response = requests.get(url)
        # Process response without validation

The Django development server itself can be leveraged in SSRF attacks when running on non-standard ports or with debug mode enabled, exposing internal services through Django's request handling.

Django-Specific Detection

Detecting SSRF in Django applications requires both manual code review and automated scanning. For code review, look for these Django-specific patterns:

URL Parameter Handling: Search for request.GET.get('url'), request.POST.get('url'), or similar patterns where URLs are accepted from user input. Check if these values are validated against a whitelist of allowed domains.

Template Context Injection: Examine templates for {{ request.GET.url }} or similar context variables that might contain user-controlled URLs. Check if ALLOWED_INCLUDE_ROOTS is properly configured.

DRF Serializers: Review custom validators in serializers that accept URLs. Look for missing validation in validate_<field> methods.

Admin Actions: Check custom admin actions that accept URLs for external operations. Verify that URL validation is implemented.

For automated detection, middleBrick's Django-specific scanning identifies SSRF vulnerabilities by testing unauthenticated endpoints with controlled payloads. The scanner attempts to access internal resources using patterns like:

http://localhost
http://127.0.0.1
http://169.254.169.254 (AWS metadata)
http://[::1]
http://metadata.google.internal (GCP metadata)

middleBrick also tests for SSRF through Django's template system by attempting to include external URLs in template rendering contexts. The scanner's Django-specific checks include:

  • Testing Django admin endpoints for SSRF in custom actions
  • Checking DRF serializers for unvalidated URL fields
  • Scanning for SSRF in Django's static/media file handling
  • Testing URL validation in custom middleware

The scanner provides Django-specific findings with severity levels and remediation guidance tailored to Django's architecture, helping developers understand exactly where and how the vulnerability exists in their Django codebase.

Django-Specific Remediation

Remediating SSRF in Django requires a defense-in-depth approach using Django's built-in features and Python libraries. Here are Django-specific remediation strategies:

URL Validation with Django's URLValidator:

from django.core.validators import URLValidator
from django.core.exceptions import ValidationError

def validate_allowed_url(url):
    validator = URLValidator()
    try:
        validator(url)
    except ValidationError:
        raise ValueError('Invalid URL format')
    
    # Whitelist allowed domains
    allowed_domains = ['api.example.com', 'cdn.example.org']
    parsed = urllib.parse.urlparse(url)
    if parsed.netloc not in allowed_domains:
        raise ValueError('URL not in allowed domains')
    
    # Block private IP ranges
    if is_private_ip(parsed.netloc):
        raise ValueError('Private IP addresses not allowed')

def is_private_ip(hostname):
    try:
        ip = socket.gethostbyname(hostname)
        return ipaddress.ip_address(ip).is_private
    except Exception:
        return False

Using Django's Middleware for Global Protection:

class SSRFMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response
    
    def __call__(self, request):
        # Check for SSRF attempts in request parameters
        for key, value in request.GET.items():
            if isinstance(value, str) and is_potential_ssrf(value):
                return JsonResponse({'error': 'Invalid URL'}, status=400)
        
        return self.get_response(request)

def is_potential_ssrf(url):
    # Check for localhost, internal IPs, and metadata services
    patterns = [
        r'localhost',
        r'127\.\d+\.\d+\.\d+',
        r'192\.168\.\d+\.\d+',
        r'10\.\d+\.\d+\.\d+',
        r'169\.254\.169\.254',
        r'metadata\.google\.internal',
    ]
    return any(re.search(pattern, url) for pattern in patterns)

DRF Serializer Validation:

from rest_framework import serializers

class SecureURLField(serializers.CharField):
    def to_internal_value(self, data):
        validate_allowed_url(data)
        return super().to_internal_value(data)

class SecureMediaSerializer(serializers.Serializer):
    file_url = SecureURLField()
    
    def validate_file_url(self, value):
        validate_allowed_url(value)
        return value

Django Admin Protection:

class SecureAdminMixin:
    def changelist_view(self, request, extra_context=None):
        # Add SSRF protection to admin views
        if 'url' in request.GET:
            validate_allowed_url(request.GET['url'])
        return super().changelist_view(request, extra_context)

class CustomAdmin(SecureAdminMixin, admin.ModelAdmin):
    def import_data(self, request, queryset):
        url = request.POST.get('data_url')
        validate_allowed_url(url)
        # Continue with safe operation

Template Security:

# settings.py
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'OPTIONS': {
            'allowed_include_roots': ['/safe/templates/'],  # Restrict includes
        },
    },
]

For comprehensive protection, combine these Django-specific mitigations with network-level controls like firewall rules and VPC configurations. The middleBrick CLI tool can help verify your remediations by scanning your Django application after implementing these fixes, ensuring that SSRF vulnerabilities are properly addressed.

Related CWEs: ssrf

CWE IDNameSeverity
CWE-918Server-Side Request Forgery (SSRF) CRITICAL
CWE-441Unintended Proxy or Intermediary (Confused Deputy) HIGH

Frequently Asked Questions

How does SSRF differ in Django compared to other frameworks?
Django's SSRF vulnerabilities often manifest through its request handling patterns, template system, and admin interface. Unlike Flask or Express, Django's built-in features like URLValidator, middleware system, and template security options provide native tools for SSRF prevention. Django's ORM and model validation patterns also influence how SSRF might appear in data import/export functionality.
Can middleBrick scan my Django application for SSRF?
Yes, middleBrick can scan any Django application by providing the base URL. The scanner tests unauthenticated endpoints for SSRF vulnerabilities, including attempts to access internal services, metadata endpoints, and localhost. It provides Django-specific findings with severity levels and remediation guidance tailored to Django's architecture. The scan takes 5-15 seconds and requires no credentials or setup.