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 ID | Name | Severity |
|---|---|---|
| CWE-20 | Improper Input Validation | HIGH |
| CWE-22 | Path Traversal | HIGH |
| CWE-74 | Injection | CRITICAL |
| CWE-77 | Command Injection | CRITICAL |
| CWE-78 | OS Command Injection | CRITICAL |
| CWE-79 | Cross-site Scripting (XSS) | HIGH |
| CWE-89 | SQL Injection | CRITICAL |
| CWE-90 | LDAP Injection | HIGH |
| CWE-91 | XML Injection | HIGH |
| CWE-94 | Code Injection | CRITICAL |
Frequently Asked Questions
Does Basic Auth prevent SQL injection in Django APIs?
What is a safe pattern for raw queries in Django when using Basic Auth?
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.