Dns Rebinding in Django with Basic Auth
Dns Rebinding in Django with Basic Auth — how this specific combination creates or exposes the vulnerability
DNS Rebinding is an application-layer attack that manipulates DNS responses to make a victim’s browser believe a remote host is a local one. In a Django application protected with HTTP Basic Authentication, combining DNS Rebinding with Basic Auth can bypass intended access controls and expose internal services.
Basic Auth in Django is commonly implemented by checking the Authorization header on each request. If a view trusts the origin IP after successful authentication, DNS Rebinding can be used to pivot from an external attacker-controlled domain to a local or internal endpoint while the browser still sends the stolen or reused Basic Auth credentials. Because the browser treats the final resolved IP as same-origin after the DNS switch, the authenticated session is reused, and Django may process requests to internal addresses that were never intended to be exposed externally.
Consider a scenario where Django’s ALLOWED_HOSTS is permissive or host header validation is bypassed. An attacker crafts a page that resolves a domain to an external IP, prompts the victim to authenticate via Basic Auth, then rapidly rebinds the DNS record to an internal IP such as 127.0.0.1 or a backend service. The browser continues to send the Basic Auth credentials with the rebounded request. If Django does not enforce strict host matching and does not validate that the request target is external, the authenticated session can be abused to interact with internal management interfaces or APIs that would otherwise be unreachable.
Because middleBrick tests unauthenticated attack surfaces, it flags DNS Rebinding as a risk when endpoints accept requests from internal networks after host-header-based authorization is insufficient. The scan examines input validation, host header handling, and whether authentication is applied at the correct layer, highlighting cases where Basic Auth does not adequately prevent internal access via rebinding.
Basic Auth-Specific Remediation in Django — concrete code fixes
Defending against DNS Rebinding in Django with Basic Auth requires strict host validation, careful header handling, and avoiding reliance on IP-based trust. Below are concrete, actionable fixes and code examples.
1. Strict ALLOWED_HOSTS and Host header validation
Ensure ALLOWED_HOSTS is explicit and does not include private or wildcard entries that could facilitate rebinding.
ALLOWED_HOSTS = ['api.example.com', 'www.example.com']
For additional safety, validate the HTTP Host header in middleware when your deployment uses proxies or load balancers:
import django.http
class HostValidationMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
host = request.get_host().split(':')[0]
allowed = {'api.example.com', 'www.example.com'}
if host not in allowed:
return django.http.HttpResponseForbidden('Invalid host header')
return self.get_response(request)
2. Do not trust request origin or IP after authentication
Basic Auth credentials are sent with each request; do not assume that a request with valid credentials originates from an expected network location. Avoid logic that grants elevated trust based on IP when authentication is used.
3. Use HTTPS and mitigate credential leakage
Always serve Basic Auth over HTTPS to prevent credential interception. In Django, enforce HTTPS with HSTS and secure cookies where applicable:
SECURE_SSL_REDIRECT = True
SECURE_HSTS_SECONDS = 31536000
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
4. Add CSRF and same-site protections for forms and state-changing endpoints
Even when using Basic Auth for APIs, ensure that any browser-based flows include CSRF protections and appropriate SameSite cookie attributes.
from django.views.decorators.csrf import csrf_protect
@csrf_protect
def my_protected_view(request):
# your logic
pass
5. Example of a hardened Basic Auth view
A secure view validates the host, checks credentials on each request, and avoids leaking internal details:
import base64
from django.http import HttpResponse, HttpResponseForbidden, JsonResponse
from django.views.decorators.http import require_http_methods
def parse_basic_auth(auth_header):
if not auth_header or not auth_header.startswith('Basic '):
return None, None
try:
decoded = base64.b64decode(auth_header.split(' ')[1]).decode('utf-8')
username, password = decoded.split(':', 1)
return username, password
except Exception:
return None, None
@require_http_methods(["GET"])
def secure_api_view(request):
host = request.get_host().split(':')[0]
allowed_hosts = {'api.example.com', 'www.example.com'}
if host not in allowed_hosts:
return HttpResponseForbidden('Invalid host')
auth = parse_basic_auth(request.META.get('HTTP_AUTHORIZATION'))
if auth != ('trusted_user', 'strong_password'):
return HttpResponse(status=401, headers={'WWW-Authenticate': 'Basic realm="API"'})
# Proceed with safe, scoped logic
return JsonResponse({'status': 'ok'})
6. Use Django’s built-in authentication where possible
For APIs, prefer token-based or session-based authentication with CSRF protection. If you must use Basic Auth, ensure it is scoped, rotated, and monitored.
7. Scan and monitor
Use tools like middleBrick to detect DNS Rebinding risks and misconfigurations around host validation and authentication layers. The CLI can be integrated into scripts to verify remediation:
# Example CLI usage
middlebrick scan https://api.example.com
For CI/CD, the GitHub Action can enforce a minimum security score before deployment, and the MCP Server allows scanning directly from AI coding assistants in your IDE.