HIGH missing tlsdjangobearer tokens

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_REDIRECT and SECURE_PROXY_SSL_HEADER only when you trust the proxy to set X-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 IDNameSeverity
CWE-319Cleartext Transmission of Sensitive Information HIGH
CWE-295Improper Certificate Validation HIGH
CWE-326Inadequate Encryption Strength HIGH
CWE-327Use of a Broken or Risky Cryptographic Algorithm HIGH
CWE-328Use of Weak Hash HIGH
CWE-330Use of Insufficiently Random Values HIGH
CWE-338Use of Cryptographically Weak PRNG MEDIUM
CWE-693Protection Mechanism Failure MEDIUM
CWE-757Selection of Less-Secure Algorithm During Negotiation HIGH
CWE-261Weak Encoding for Password HIGH

Frequently Asked Questions

Can I safely use Bearer tokens over HTTP in development with DEBUG=True?
You can during local development with DEBUG=True, but you should still use HTTPS to mimic production and avoid forming insecure habits. Never rely on HTTP in production; always enforce SECURE_SSL_REDIRECT and SECURE_PROXY_SSL_HEADER behind a trusted proxy.
Does enabling TLS alone protect Bearer tokens from all risks?
TLS protects tokens in transit, but tokens can still be leaked via logs, client-side storage, or insecure referrer headers. Combine HTTPS with secure token generation, short lifetimes, scope restrictions, and server-side validation to reduce overall risk.