HIGH dns cache poisoningdjangobearer tokens

Dns Cache Poisoning in Django with Bearer Tokens

Dns Cache Poisoning in Django with Bearer Tokens — how this specific combination creates or exposes the vulnerability

DNS cache poisoning (also known as DNS spoofing) occurs when an attacker corrupts the resolver cache with forged DNS responses, redirecting a victim to a malicious IP. In Django applications that rely on external service discovery or microservice communication, poisoned DNS entries can cause requests to be sent to an attacker-controlled host. When those requests include Bearer tokens, the combination can expose privileged authentication material or allow an attacker to act on behalf of the victim.

Consider a Django service that resolves an internal auth host via DNS at runtime, then forwards Authorization: Bearer headers to that host. If an attacker can poison the DNS cache for that hostname (for example via a vulnerable resolver or a compromised upstream DNS server), the Django application may unknowingly send Bearer tokens to the attacker. This can lead to token theft or unauthorized actions if the token is reused across services. The risk is especially relevant when tokens are long-lived or when the Django app runs in environments where DNS resolution is shared across containers or VMs.

Django itself does not perform DNS caching in user code, but the underlying OS resolver and any HTTP client used (such as requests or httpx) will. Therefore, the exposure arises from how the application uses Bearer tokens in combination with external hostnames that are subject to DNS resolution. For example, if a Django backend calls an identity provider endpoint via a hostname that can be poisoned, and the request includes a Bearer token, intercepted or altered traffic may compromise the token.

Real-world attack patterns include intercepting requests to an OAuth introspection endpoint or a backend API gateway identified by a friendly hostname. If an API expects Bearer token authorization and the hostname resolves to the wrong IP due to cache poisoning, tokens can be leaked to an attacker who terminates TLS or proxies traffic. This maps to OWASP API Top 10 controls around authentication and integrity issues and can be relevant to compliance frameworks such as PCI-DSS and SOC2 when token confidentiality is required.

To detect such risks, scans should validate that services using Bearer tokens do not rely on untrusted or shared DNS resolution for critical endpoints and that transport security is enforced. middleBrick checks for insecure handling of authentication in combination with host resolution and flags scenarios where tokens could be exposed via network-layer weaknesses.

Bearer Tokens-Specific Remediation in Django — concrete code fixes

Remediation focuses on ensuring that token handling is resilient to DNS manipulation by avoiding reliance on mutable DNS records for authorization and by hardening HTTP clients. Use explicit IPs or service discovery mechanisms that are not subject to cache poisoning where possible, and enforce strict transport security. Below are concrete patterns and code examples for Django projects.

1. Use HTTPS with certificate verification and avoid hostname-based routing for token endpoints

Always verify TLS certificates and avoid falling back to HTTP. Pin or explicitly trust certificate authorities for critical endpoints.

import requests

# Good: explicit HTTPS with cert verification and a pinned fingerprint or CA
response = requests.get(
    'https://auth.example.com/introspect',
    headers={'Authorization': 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'},
    verify='/path/to/ca-bundle.pem',  # or True (default) with proper CA store
    timeout=5,
)

2. Configure HTTP clients to use specific IPs or SRV records when DNS must be used

If you must rely on DNS, prefer SRV records and validate resolved endpoints. For high-security scenarios, consider static IPs or a service mesh with mTLS to reduce DNS dependency.

import httpx
import ssl

# Example using httpx with custom resolver settings (platform-specific)
# Prefer mTLS client certificates for additional assurance
ssl_context = ssl.create_default_context(cafile='/path/to/ca-bundle.pem')
client = httpx.Client(
    headers={'Authorization': 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'},
    verify=ssl_context,
    follow_redirects=False,
)
resp = client.get('https://auth.example.com/token')

3. Validate and restrict scopes and audiences in token introspection

When using opaque tokens, introspect them via a trusted endpoint and validate audience, issuer, and scopes. Do not trust hostname-derived metadata alone.

from django.http import JsonResponse
import requests

def introspect_token(request):
    token = request.headers.get('Authorization', '').replace('Bearer ', '')
    resp = requests.post(
        'https://auth.example.com/introspect',
        data={'token': token, 'client_id': 'django-app'},
        auth=('django-client', 'django-client-secret'),
        verify=True,
    )
    if resp.status_code == 200:
        data = resp.json()
        if data.get('active') and data.get('scope') and 'api:read' in data['scope'].split():
            return JsonResponse({'status': 'active', 'scope': data['scope']})
    return JsonResponse({'error': 'invalid_token'}, status=401)

4. Use short-lived tokens and refresh rotation to limit exposure

Prefer JWTs with short expirations and implement refresh token rotation. Store refresh tokens securely and avoid logging Authorization headers.

# Example middleware to reject tokens with excessive lifetime
import jwt
from django.conf import settings
from django.http import HttpResponseForbidden

class TokenExpiryMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        auth = request.headers.get('Authorization', '')
        if auth.startswith('Bearer '):
            token = auth.split(' ')[1]
            try:
                payload = jwt.decode(token, options={'verify_signature': False})
                exp = payload.get('exp')
                if exp:
                    # reject tokens with lifetime longer than threshold
                    import time
                    if exp - payload.get('iat', exp) > 300:  # 5 minutes max
                        return HttpResponseForbidden('Token lifetime too long')
            except Exception:
                pass  # let downstream handle invalid tokens
        return self.get_response(request)

5. Monitor and rotate credentials, and use mTLS where feasible

Rotate client secrets and API keys regularly. Use mutual TLS for service-to-service calls to reduce reliance on bearer tokens for authentication. middleBrick scans can help identify missing transport security and weak authentication configurations.

Frequently Asked Questions

Can DNS cache poisoning affect Django even if the app uses HTTPS?
Yes. HTTPS protects content in transit, but if the hostname used in the Authorization header's target endpoint is resolved to a malicious IP via poisoned DNS, the request may be sent to an attacker who can terminate TLS. Use strict certificate validation and avoid relying on mutable DNS for critical endpoints.
How does middleBrick help detect risks related to Bearer tokens and DNS issues?
middleBrick scans unauthenticated attack surfaces and checks for insecure authentication handling alongside host resolution paths. It flags scenarios where tokens may be exposed due to weak transport configurations or lack of validation, complementing remediation such as HTTPS enforcement and token introspection.