Skip to main content

Django Request Guard

A reusable Django middleware package for blocking automated scanners and bots attempting to access sensitive or suspicious paths.

  • Django
  • Python
  • Wagtail

Overview

Django Request Guard is a reusable Django middleware package designed to block common automated requests for sensitive files and application paths. Public websites routinely receive scanner and bot traffic looking for exposed environment files, configuration data, known vulnerabilities, and resources associated with platforms such as WordPress or Drupal—even when those technologies are not used by the site.

Request Guard identifies these requests early in Django's request lifecycle and rejects them before they reach the application's normal views and processing. In addition to reducing unnecessary application work, this can limit the resources consumed by automated traffic and keep application logs focused on more meaningful activity.

The package includes built-in protection for commonly targeted paths and supports configurable rules that can be maintained centrally and shared across multiple Django applications. Remote configuration is optional and fail-safe: if it cannot be retrieved or validated, the application continues running with its built-in protections.

Request Guard is intended as an application-level layer of protection, not a replacement for infrastructure-level security such as a CDN, web application firewall, or other upstream traffic filtering. Its purpose is to give Django applications a simple and centrally manageable way to reject requests that have no legitimate reason to reach normal application processing.

Request Filtering

Django Request Guard runs as middleware, allowing suspicious requests to be identified and rejected before they reach the application's normal views and processing. The package includes built-in protections for paths commonly targeted by automated scanners, including environment files, SSH-related paths, and Django management files.

Keeping this filtering at the middleware layer provides a single point of protection for the entire Django application. Individual views and applications do not need to implement their own checks for these requests, and unwanted traffic can be stopped early in the request lifecycle.

Rejecting unwanted requests early also reduces unnecessary application processing and keeps routine scanner traffic from consuming resources intended for legitimate visitors. On applications where requests consume metered compute resources, this can also reduce the operational cost associated with automated traffic. Filtering known scanner requests helps keep application logs focused on meaningful activity and reduces the amount of irrelevant traffic developers need to investigate.

Request Guard is intended as an application-level layer rather than a replacement for infrastructure-level protections such as a CDN or web application firewall. Its role is to give Django applications a simple, centrally configurable way to reject requests that should never require normal application processing.

Configurable Rules

In addition to its built-in protections, Request Guard supports custom rules defined in JSON. Rules can match paths that contain specified values or begin with specified prefixes, making it possible to respond to scanning patterns that are specific to an application or emerge over time.

This keeps frequently changing security rules separate from the Python package itself. New paths can be blocked without modifying the middleware code, while a small set of built-in rules remains available as a baseline.

Configurable rules can also block scanning activity targeting software that the Django application does not use. Public websites routinely receive automated requests looking for known WordPress, Drupal, PHP, and other platform-specific files and vulnerabilities regardless of the site's actual technology stack. A Django site may not be vulnerable to those exploits, but the requests still create unnecessary traffic and application processing. Request Guard can identify and reject these known patterns without requiring the application to pretend that the requested resources exist.

For example, a Django application that does not run WordPress can reject requests for paths such as /wp-admin/, /wp-login.php, or /wp-content/. Similar rules can be added for scanner traffic targeting other platforms or known vulnerability paths that have no legitimate purpose on the application.

Centralized Configuration

For environments with multiple Django applications, Request Guard can load additional rules from a JSON file stored in Amazon S3. The S3 bucket, object key, AWS region, connection timeouts, and optional credentials are configured through environment variables, making the same package suitable for different deployment environments.

Each web process downloads and validates the configured rules when it starts. This allows a shared rule set to be maintained in one location and applied across multiple websites rather than maintaining duplicate lists within every application's codebase. With Gunicorn preloading, rules can be loaded before workers are forked; otherwise, individual workers load their own copy at startup.

Fail-Safe Behavior

Remote configuration is intentionally optional. If S3 is unavailable or the downloaded configuration is invalid, the application continues to start and Request Guard falls back to its built-in protection rules.

This avoids turning an additional security measure into a new point of failure. A temporary AWS, network, credential, or configuration problem does not prevent the website from running, while the package's baseline protections remain active.

Reuse Across Sites

Request Guard was designed as a reusable Django package rather than security logic tied to a single website. Installation consists of adding the package and its middleware to a Django project, with additional configuration supplied through environment variables when centralized rules are needed.

That separation allows the middleware code to remain consistent across projects while the shared rule set evolves independently. For organizations maintaining multiple Django applications, a newly identified scanning pattern can therefore be added to the centralized configuration rather than implemented separately in every codebase.