Missing Tls in Django with Bearer Tokens
Missing Tls in Django with Bearer Tokens — how this specific combination creates or exposes the vulnerability
When a Django API relies on Bearer Tokens for authorization but does not enforce Transport Layer Security (TLS), tokens can be intercepted in transit. This combination violates a core security principle: confidentiality in transit. Without TLS, any network point between the client and server can observe or modify cleartext HTTP traffic, including the Authorization header that carries the Bearer token.
Django’s built-in development server does not enable TLS, and if a production deployment terminates TLS at a load balancer or proxy but still allows cleartext HTTP internally, or if TLS is misconfigured (e.g., weak ciphers, missing HSTS), the token remains exposed. An attacker performing network sniffing, session hijacking, or a man-in-the-middle (MITM) attack can capture the token and impersonate the victim indefinitely, as Bearer tokens are typically long-lived compared to session cookies with additional protections like Secure and HttpOnly flags.
For example, a request like Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 sent over HTTP reveals the token to anyone who can observe the packet flow. This exposure enables unauthorized access to protected endpoints, data exfiltration, and potential abuse of privileged operations. The risk is amplified if the token is valid across multiple services or has broad scopes, aligning with common findings in BOLA/IDOR and Data Exposure checks that middleBrick reports when TLS is missing.
Compliance frameworks such as OWASP API Top 10 (API1:2023 Broken Object Level Authorization often coexists with missing transport security) and standards like PCI-DSS explicitly require encryption in transit for any authentication or authorization token. Without TLS, even robust token generation and scoping do not prevent interception. middleBrick’s scans detect unencrypted transport during its Encryption and Authentication checks, highlighting missing TLS as a high-severity finding that precedes token compromise.
Developers must ensure that all API endpoints—especially those validating Bearer tokens—are served exclusively over HTTPS, with strong cipher suites and proper certificate management. Middleware should reject cleartext HTTP requests before any token validation logic runs, ensuring that a missing TLS configuration is caught early in CI/CD rather than in a production incident.
Bearer Tokens-Specific Remediation in Django — concrete code fixes
Remediation focuses on enforcing TLS and ensuring tokens are only handled over encrypted channels. In Django, you can enforce HTTPS at the application and proxy levels, improve token handling in views, and validate the security of incoming requests.
1. Enforce HTTPS site-wide
Configure Django to assume HTTPS is provided by a proxy or load balancer and to reject non-secure requests:
import os
from pathlib import Path
BASE_DIR = Path(__file__).resolve().parent.parent
SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY', 'django-insecure-#example-insecure-key-for-dev-only')
DEBUG = False
ALLOWED_HOSTS = ['api.example.com']
# Require HTTPS via proxy headers; set behind a trusted load balancer
SECURE_SSL_REDIRECT = True
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
# HSTS (HTTP Strict Transport Security) — adjust max-age as needed
SECURE_HSTS_SECONDS = 31536000
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_HSTS_PRELOAD = True
2. Validate request security before token usage
In views that consume Bearer tokens, explicitly verify the request is secure before processing authentication:
from django.conf import settings
from django.http import JsonResponse
from django.views import View
class ProtectedApiView(View):
def dispatch(self, request, *args, **kwargs):
# Reject cleartHTTP in production
if not request.is_secure() and settings.DEBUG is False:
return JsonResponse({'error': 'HTTPS required'}, status=403)
return super().dispatch(request, *args, **kwargs)
def get(self, request):
auth = request.headers.get('Authorization', '')
if not auth.startswith('Bearer '):
return JsonResponse({'error': 'Invalid authorization header'}, status=401)
token = auth.split(' ', 1)[1]
# Validate token and proceed
return JsonResponse({'data': 'protected resource'})
3. Use middleware to reject HTTP early
Add a lightweight middleware to block non-HTTPS requests when not in development:
class EnforceHttpsMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
if not request.is_secure() and not settings.DEBUG:
from django.http import HttpResponse
return HttpResponse('HTTPS required', status=403)
return self.get_response(request)
Then add it to MIDDLEWARE in settings.py near the top (after security-related middleware):
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'path.to.EnforceHttpsMiddleware',
'django.middleware.common.CommonMiddleware',
# ...
]
4. Example of secure token validation pattern
When validating tokens, ensure the request method and path are inspected, and avoid logging tokens:
import logging
from django.http import JsonResponse
logger = logging.getLogger(__name__)
def validate_bearer_token(request):
auth = request.headers.get('Authorization', '')
if not auth.lower().startswith('bearer '):
return None
token = auth.split(' ', 1)[1]
# Avoid logging the token
logger.info('Validating bearer token for request to %s', request.path)
# Perform token lookup and validation
if token == os.environ.get('EXPECTED_TEST_TOKEN'):
return {'user_id': 1, 'scopes': ['read', 'write']}
return None
5. Complementary practices
- Use a reverse proxy or load balancer (e.g., Nginx, HAProxy, AWS ALB) to terminate TLS with strong ciphers and forward only to Django over HTTPS internally.
- Set
SECURE_SSL_REDIRECTandSECURE_PROXY_SSL_HEADERonly when you trust the proxy to setX-Forwarded-Proto. - Rotate Bearer tokens regularly and scope them to least privilege to reduce impact if exposure occurs despite TLS enforcement.
Related CWEs: encryption
| CWE ID | Name | Severity |
|---|---|---|
| CWE-319 | Cleartext Transmission of Sensitive Information | HIGH |
| CWE-295 | Improper Certificate Validation | HIGH |
| CWE-326 | Inadequate Encryption Strength | HIGH |
| CWE-327 | Use of a Broken or Risky Cryptographic Algorithm | HIGH |
| CWE-328 | Use of Weak Hash | HIGH |
| CWE-330 | Use of Insufficiently Random Values | HIGH |
| CWE-338 | Use of Cryptographically Weak PRNG | MEDIUM |
| CWE-693 | Protection Mechanism Failure | MEDIUM |
| CWE-757 | Selection of Less-Secure Algorithm During Negotiation | HIGH |
| CWE-261 | Weak Encoding for Password | HIGH |