Skip to main content

Security and Authentication

This project provides a robust security and authentication framework centered around middleware, cryptographic signing, and a flexible user authentication system. These components work together to protect against common web vulnerabilities while providing a consistent API for managing user sessions.

User Authentication

The core authentication logic resides in django.contrib.auth. It decouples the verification of credentials from the management of user sessions, allowing for both synchronous and asynchronous workflows.

Authentication and Session Management

The framework provides three primary functions for handling users, located in django/contrib/auth/__init__.py:

  • authenticate(request=None, **credentials): Verifies credentials against a list of configured backends (defined in settings.AUTHENTICATION_BACKENDS). If valid, it returns a user object annotated with the backend used.
  • login(request, user, backend=None): Persists a user's ID in the session using the SESSION_KEY (_auth_user_id). It also handles session rotation via rotate_token(request) to prevent session fixation attacks.
  • logout(request): Completely clears the session data and removes the authenticated user's ID from the request.

For asynchronous environments, the framework provides aauthenticate(), alogin(), and alogout(). These functions utilize asgiref.sync.sync_to_async or native async implementations to avoid blocking the event loop.

Authentication Backends

Authentication is extensible through backends. The _get_backends() function in django/contrib/auth/__init__.py loads the classes specified in settings.AUTHENTICATION_BACKENDS. By default, this typically includes django.contrib.auth.backends.ModelBackend.

Built-in Views

The django.contrib.auth.views module provides standard implementations for common tasks. For example, LoginView (a subclass of FormView) handles the login logic:

# django/contrib/auth/views.py

class LoginView(RedirectURLMixin, FormView):
# ...
def form_valid(self, form):
"""Security check complete. Log the user in."""
auth_login(self.request, form.get_user())
return HttpResponseRedirect(self.get_success_url())

CSRF Protection

The CsrfViewMiddleware in django/middleware/csrf.py provides protection against Cross-Site Request Forgery. It ensures that "unsafe" HTTP methods (POST, PUT, DELETE, PATCH) contain a valid CSRF token that matches the secret stored in the user's cookie or session.

How it Works

  1. Token Generation: The get_token(request) function generates a masked CSRF secret.
  2. Validation: For non-safe methods, process_view calls _check_token(request). This compares the token provided in the request (either in POST data as csrfmiddlewaretoken or in the X-CSRFToken header) against the csrf_secret retrieved via _get_secret(request).
  3. Strict Referer Checking: For HTTPS requests, the middleware performs strict referer checking in _check_referer(request) to ensure the request originated from a trusted domain.

Configuration

  • CSRF_USE_SESSIONS: If True, the CSRF secret is stored in request.session under the _csrftoken key instead of a cookie. This requires SessionMiddleware to be placed before CsrfViewMiddleware.
  • CSRF_TRUSTED_ORIGINS: A list of hosts trusted for cross-site unsafe requests. The middleware uses _origin_verified(request) to validate the HTTP_ORIGIN header against this list.

Cryptographic Signing

The django.core.signing module provides a way to generate URL-safe signed JSON objects. This is used to protect data sent to untrusted environments (like a user's browser) from tampering.

Signer and TimestampSigner

The Signer class uses HMAC with SHA-256 (by default) to sign values.

# django/core/signing.py usage example
from django.core import signing
signer = signing.Signer()
value = signer.sign('hello')
# Result: 'hello:signature'

TimestampSigner extends Signer by appending a base62-encoded timestamp to the value. This allows for expiring signatures using the max_age parameter in unsign():

# django/core/signing.py
class TimestampSigner(Signer):
def unsign(self, value, max_age=None):
# ... checks if (current_time - timestamp) > max_age

High-level API

The dumps() and loads() functions provide a high-level interface for signing complex objects. They use a JSONSerializer to convert objects to strings before signing and support optional compression via zlib.

Security Middleware

The SecurityMiddleware in django/middleware/security.py implements several HTTP-level security enhancements based on project settings:

  • SSL Redirection: If SECURE_SSL_REDIRECT is enabled, it redirects all non-HTTPS requests to HTTPS.
  • HSTS: Sets the Strict-Transport-Security header if SECURE_HSTS_SECONDS is configured.
  • Content-Type Sniffing: Sets X-Content-Type-Options: nosniff if SECURE_CONTENT_TYPE_NOSNIFF is True.
  • Referrer Policy: Sets the Referrer-Policy header based on SECURE_REFERRER_POLICY.

Additionally, XFrameOptionsMiddleware (in django/middleware/clickjacking.py) sets the X-Frame-Options header to prevent clickjacking attacks, defaulting to the value in settings.X_FRAME_OPTIONS (usually SAMEORIGIN).

Key Security Settings

SettingDescription
SECRET_KEYUsed for all cryptographic signing and CSRF secret generation.
AUTHENTICATION_BACKENDSDefines the classes used to verify user credentials.
AUTH_USER_MODELThe model used to represent users (retrieved via get_user_model()).
CSRF_COOKIE_HTTPONLYWhether the CSRF cookie should be accessible via JavaScript.
SECURE_HSTS_SECONDSDuration for the HSTS header.
X_FRAME_OPTIONSControls whether the site can be embedded in an iframe.