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.