HIGH sql injectiondjangobasic auth

Sql Injection in Django with Basic Auth

Sql Injection in Django with Basic Auth — how this specific combination creates or exposes the vulnerability

SQL injection remains a critical risk in Django when developer patterns do not enforce strict separation between SQL and data. This risk is observable in APIs protected only by HTTP Basic Authentication, where authentication is lightweight but does not change how queries are built. Basic Auth typically validates a username and password against a user model, often using Django’s built-in authentication utilities. If the API then uses request parameters, headers, or dynamic query fragments to build database statements, injection paths remain present regardless of the auth mechanism.

Consider a view that uses Basic Auth via django.contrib.auth.authenticate and then builds a dynamic query using string formatting or concatenation. Even when credentials are verified, unsafe query construction can allow an attacker to manipulate the SQL statement. For example, concatenating user input directly into WHERE clauses or using cursor.execute with unsanitized strings exposes the application. The combination is notable because Basic Auth does not provide parameterization guarantees; developers must still apply Django’s safe patterns. Attackers can probe endpoints with crafted payloads to extract data, bypass authentication logic, or infer database structure.

An OpenAPI contract may define query parameters such as search or user_id. If runtime code uses these values directly in raw SQL, the API surface remains vulnerable despite authentication. Real-world attack patterns include using tautologies (e.g., ' OR 1=1 --) to bypass intended filters or using stacked queries to perform read operations on other tables. Injection findings from scans often map to OWASP API Top 10 A03:2023 — Injection, and may intersect with compliance frameworks such as PCI-DSS and SOC2 when sensitive data is exposed.

Django provides several safe mechanisms, including the ORM and connection.cursor with parameterized queries, to avoid these pitfalls. However, if developers bypass the ORM or use raw queries without placeholders, the risk persists. Continuous scanning with tools that inspect both spec definitions and runtime behavior can detect mismatches between declared parameters and actual query construction, highlighting areas where authentication does not mitigate injection risks.

Basic Auth-Specific Remediation in Django — concrete code fixes

Remediation centers on using Django’s ORM and parameterized queries consistently, regardless of the authentication method. When Basic Auth is used for endpoint protection, developers must ensure that any database interaction treats all external input as data, not executable SQL. Below are concrete patterns and code examples that reduce injection risk while retaining Basic Auth for access control.

1. Prefer Django’s ORM with parameterized filters

The ORM automatically parameterizes inputs, making injection significantly harder. Use filter, exclude, and get with keyword arguments instead of constructing SQL fragments.

from django.contrib.auth.models import User
from django.http import JsonResponse
from django.views import View

class UserDetailView(View):
    def get(self, request, user_id):
        # Safe: ORM parameterization prevents injection
        try:
            user = User.objects.get(pk=user_id)
            return JsonResponse({'username': user.username, 'email': user.email})
        except User.DoesNotExist:
            return JsonResponse({'error': 'Not found'}, status=404)

2. Use connection.cursor with placeholders for raw queries

If raw SQL is necessary, always use parameterized queries with placeholders. Never interpolate variables into the SQL string.

from django.db import connection
from django.http import JsonResponse

def search_users(request):
    search_term = request.GET.get('q', '')
    with connection.cursor() as cursor:
        # Safe: parameterized query with placeholders
        cursor.execute('SELECT id, username FROM auth_user WHERE username LIKE %s', [f'%{search_term}%'])
        rows = cursor.fetchall()
    results = [{'id': row[0], 'username': row[1]} for row in rows]
    return JsonResponse(results, safe=False)

3. Validate and sanitize input even with Basic Auth

Basic Auth verifies identity but does not validate data formats. Explicit validation and length checks reduce unexpected behavior.

from django.core.validators import MinLengthValidator, RegexValidator
from django.core.exceptions import ValidationError
from django.http import JsonResponse

def validate_username(value):
    validator = RegexValidator(r'^[\w.@+-]+$', 'Enter a valid username.')
    validator(value)

def get_user_profile(request):
    username = request.GET.get('username', '')
    try:
        validate_username(username)
        # Safe: validated input used with ORM
        user = User.objects.filter(username=username).first()
        if user:
            return JsonResponse({'username': user.username, 'email': user.email})
        return JsonResponse({'error': 'Not found'}, status=404)
    except ValidationError as e:
        return JsonResponse({'error': e.messages}, status=400)

4. Middleware and authentication integration

Ensure that Basic Auth is implemented using Django’s authentication classes, which integrate cleanly with permission checks and keep credential handling consistent.

from django.contrib.auth.models import User
from django.http import JsonResponse
from django.contrib.auth import authenticate

def login_basic(request):
    username = request.META.get('HTTP_USERNAME', '')
    password = request.META.get('HTTP_PASSWORD', '')
    user = authenticate(request, username=username, password=password)
    if user is not None:
        return JsonResponse({'status': 'authenticated', 'username': user.username})
    return JsonResponse({'error': 'Invalid credentials'}, status=401)

5. Continuous scanning and compliance mapping

Use scanning solutions that correlate runtime behavior with OpenAPI specs to highlight mismatches. Findings can be mapped to frameworks such as OWASP API Top 10 and compliance requirements, and plans that include continuous monitoring can help detect regressions early.

Related CWEs: inputValidation

CWE IDNameSeverity
CWE-20Improper Input Validation HIGH
CWE-22Path Traversal HIGH
CWE-74Injection CRITICAL
CWE-77Command Injection CRITICAL
CWE-78OS Command Injection CRITICAL
CWE-79Cross-site Scripting (XSS) HIGH
CWE-89SQL Injection CRITICAL
CWE-90LDAP Injection HIGH
CWE-91XML Injection HIGH
CWE-94Code Injection CRITICAL

Frequently Asked Questions

Does Basic Auth prevent SQL injection in Django APIs?
No. Basic Auth handles credential verification but does not protect against unsafe query construction. Injection risk depends on how inputs are used in database queries, so parameterized queries and the ORM remain essential.
What is a safe pattern for raw queries in Django when using Basic Auth?
Always use parameterized placeholders with cursor.execute (e.g., cursor.execute('SELECT * FROM table WHERE id = %s', [value])) or prefer Django’s ORM methods like filter and get to avoid injection.