How to Set Security Headers in Django for Safer Web Apps
In Django, you set security headers by adding middleware or configuring settings like
SECURE_BROWSER_XSS_FILTER and SECURE_CONTENT_TYPE_NOSNIFF. You can also add custom headers using middleware to enhance protection against attacks such as XSS and clickjacking.Syntax
Django provides built-in settings and middleware to set common security headers. You can enable them in your settings.py file or create custom middleware to add headers manually.
Key settings include:
SECURE_BROWSER_XSS_FILTER = True- Enables the XSS filter in browsers.SECURE_CONTENT_TYPE_NOSNIFF = True- Prevents MIME type sniffing.X_FRAME_OPTIONS = 'DENY'- Prevents clickjacking by disallowing framing.
For custom headers, middleware must implement a __call__ or process_response method to add headers to the response.
python
class SecurityHeadersMiddleware: def __init__(self, get_response): self.get_response = get_response def __call__(self, request): response = self.get_response(request) response['X-Content-Type-Options'] = 'nosniff' response['X-Frame-Options'] = 'DENY' response['X-XSS-Protection'] = '1; mode=block' return response
Example
This example shows how to enable Django's built-in security settings and add a custom middleware to set extra headers.
python
# settings.py SECURE_BROWSER_XSS_FILTER = True SECURE_CONTENT_TYPE_NOSNIFF = True X_FRAME_OPTIONS = 'DENY' MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.middleware.common.CommonMiddleware', 'myapp.middleware.SecurityHeadersMiddleware', # Custom middleware # other middleware... ] # myapp/middleware.py class SecurityHeadersMiddleware: def __init__(self, get_response): self.get_response = get_response def __call__(self, request): response = self.get_response(request) response['Referrer-Policy'] = 'no-referrer' response['Permissions-Policy'] = 'geolocation=()' return response
Output
When running the Django app, HTTP responses will include headers:
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
Referrer-Policy: no-referrer
Permissions-Policy: geolocation=()
Common Pitfalls
- Forgetting to add your custom middleware to the
MIDDLEWARElist insettings.py. - Setting conflicting headers manually and via Django settings can cause unexpected behavior.
- Not using
SecurityMiddlewarewhich handles some headers automatically. - Relying only on headers without HTTPS; headers like
Strict-Transport-Securityrequire HTTPS to be effective.
python
## Wrong: Missing middleware registration # myapp/middleware.py class SecurityHeadersMiddleware: def __init__(self, get_response): self.get_response = get_response def __call__(self, request): response = self.get_response(request) response['X-Frame-Options'] = 'DENY' return response # settings.py MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', # 'myapp.middleware.SecurityHeadersMiddleware' is missing here ] ## Right: Add middleware to settings MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'myapp.middleware.SecurityHeadersMiddleware', ]
Quick Reference
| Setting / Header | Purpose | Example Value |
|---|---|---|
| SECURE_BROWSER_XSS_FILTER | Enable browser XSS filter | True |
| SECURE_CONTENT_TYPE_NOSNIFF | Prevent MIME sniffing | True |
| X_FRAME_OPTIONS | Prevent clickjacking | 'DENY' or 'SAMEORIGIN' |
| Strict-Transport-Security | Force HTTPS (set via middleware) | 'max-age=31536000; includeSubDomains' |
| Referrer-Policy | Control referrer info sent | 'no-referrer' |
| Permissions-Policy | Control browser features | 'geolocation=()' |
Key Takeaways
Use Django's built-in security settings like SECURE_BROWSER_XSS_FILTER and X_FRAME_OPTIONS to set common headers easily.
Add custom security headers by creating middleware that modifies the response headers.
Always register your custom middleware in the MIDDLEWARE list in settings.py.
Combine security headers with HTTPS for full protection, especially for headers like Strict-Transport-Security.
Test your headers using browser DevTools or online tools to ensure they are correctly applied.