HIGH broken authenticationdjangobasic auth

Broken Authentication in Django with Basic Auth

Broken Authentication in Django with Basic Auth — how this specific combination creates or exposes the vulnerability

Basic Authentication over unencrypted channels is a common cause of broken authentication in Django. When Basic Auth is used without TLS, credentials are base64-encoded but not encrypted, making them trivially recoverable to anyone who can observe the traffic. base64 is not encryption; it is an encoding that can be decoded in a single step. An attacker performing passive sniffing on the network can intercept the Authorization header and immediately decode it to obtain the username and password.

Django’s built-in django.contrib.auth.authentication.BasicAuthentication (used typically with API views or when paired with permission classes like IsAuthenticated) will validate the provided credentials against Django’s user store. If the transport is not protected, the authentication boundary is effectively bypassed because the secret (password) is exposed in transit. This aligns with OWASP API Top 10:2023 — API1:2023 Broken Object Level Authorization often intersects with API2:2023 Broken Authentication when transport protections are missing.

Even when TLS is used, misconfiguration can reintroduce risk. For example, if your Django application accepts both HTTP and HTTPS and does not enforce secure transport, a user agent may inadvertently downgrade to HTTP. Additionally, storing credentials in source code or environment variables without restricting file permissions can lead to exposure in logs or error pages. MiddleBrick’s unauthenticated scan would flag such endpoints under Data Exposure and Authentication checks, noting that Basic Auth credentials are traversable without adequate transport protection.

Consider a typical pattern where Basic Auth is applied via a decorator or permission:

from django.contrib.auth.decorators import login_required
from django.http import HttpResponse
from django.views.decorators.http import require_http_methods
import base64

def basic_auth_required(view_func):
    def wrapper(request, *args, **kwargs):
        auth = request.META.get('HTTP_AUTHORIZATION', '')
        if not auth.lower().startswith('basic '):
            return HttpResponse('Unauthorized', status=401)
        encoded = auth.split(' ', 1)[1]
        # This is illustrative; avoid manual decoding in production
        decoded = base64.b64decode(encoded).decode('utf-8')
        username, password = decoded.split(':', 1)
        # naive validation (not recommended)
        from django.contrib.auth import authenticate
        user = authenticate(username=username, password=password)
        if user is not None:
            request.user = user
            return view_func(request, *args, **kwargs)
        return HttpResponse('Unauthorized', status=401)
    return wrapper

@require_http_methods(["GET"])
@basic_auth_required
def my_protected_view(request):
    return HttpResponse('OK')

This approach is fragile: it does not leverage Django’s built-in authentication backends properly, mishandles realm and quality-of-protection parameters, and does not integrate with session or token mechanisms. Moreover, if the view is accidentally cached or logged, the Authorization header may be persisted in server logs, further increasing exposure. MiddleBrick’s checks for Authentication and Property Authorization would highlight such implementation gaps.

Basic Auth-Specific Remediation in Django — concrete code fixes

Remediation centers on eliminating Basic Auth for browser-based or high-risk APIs and, when unavoidable, enforcing strict transport and storage controls. The primary fix is to disable Basic Auth and adopt token-based authentication such as OAuth 2.0 or JWT over HTTPS. If you must retain Basic Auth in a controlled environment (e.g., machine-to-machine with mTLS), enforce HTTPS and never rely on it over HTTP.

First, ensure your Django application enforces HTTPS via SECURE_SSL_REDIRECT and HSTS:

# settings.py
SECURE_SSL_REDIRECT = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
SECURE_HSTS_SECONDS = 31536000
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_HSTS_PRELOAD = True

Next, prefer Django REST Framework’s built-in authentication classes, which integrate cleanly with permissions and avoid manual credential parsing:

from rest_framework.permissions import IsAuthenticated
from rest_framework.authentication import BasicAuthentication
from rest_framework.views import APIView
from rest_framework.response import Response

class SecureBasicAuthView(APIView):
    authentication_classes = [BasicAuthentication]
    permission_classes = [IsAuthenticated]

    def get(self, request):
        # request.user is already authenticated by BasicAuthentication over HTTPS
        return Response({'status': 'ok', 'user': request.user.username})

Even with DRF’s BasicAuthentication, you must ensure that no middleware or logging captures the Authorization header. Use middleware to strip or redact sensitive headers before logging. Also, rotate credentials frequently and avoid using shared or service accounts with elevated privileges.

For new projects, replace Basic Auth with token-based flows. Example using TokenAuthentication:

from rest_framework.authentication import TokenAuthentication
from rest_framework.permissions import IsAuthenticated

class TokenAuthView(APIView):
    authentication_classes = [TokenAuthentication]
    permission_classes = [IsAuthenticated]

    def get(self, request):
        return Response({'status': 'authenticated', 'user': request.user.username})

Finally, incorporate scanning in your CI/CD pipeline to detect regressions. The middleBrick GitHub Action can fail builds if an endpoint exposed over HTTP uses weak authentication patterns, ensuring that insecure configurations are caught before deployment.

Related CWEs: authentication

CWE IDNameSeverity
CWE-287Improper Authentication CRITICAL
CWE-306Missing Authentication for Critical Function CRITICAL
CWE-307Brute Force HIGH
CWE-308Single-Factor Authentication MEDIUM
CWE-309Use of Password System for Primary Authentication MEDIUM
CWE-347Improper Verification of Cryptographic Signature HIGH
CWE-384Session Fixation HIGH
CWE-521Weak Password Requirements MEDIUM
CWE-613Insufficient Session Expiration MEDIUM
CWE-640Weak Password Recovery HIGH

Frequently Asked Questions

Is Basic Auth ever acceptable in Django APIs?
Only in tightly controlled environments with mutual TLS or IP restrictions, and always over HTTPS. Prefer token-based authentication; treat Basic Auth as legacy for browser-facing APIs due to inherent credential exposure risks.
How does middleBrick help detect Basic Auth risks?
MiddleBrick’s Authentication and Data Exposure checks identify endpoints using Basic Auth over unencrypted transport and highlight missing HTTPS enforcement, providing remediation guidance to tighten authentication handling.