Django Security Settings
Introduction
Security is a critical aspect of web development. Django, as a mature web framework, comes with several built-in security features that can be configured through its settings module. Properly configuring these security settings helps protect your application against common threats like cross-site scripting (XSS), cross-site request forgery (CSRF), clickjacking, and other vulnerabilities.
In this tutorial, we'll explore Django's key security settings, understand their purpose, and learn how to configure them correctly for your projects.
Django's Security Philosophy
Django follows the principle of "secure by default." Many security features are enabled automatically when you create a new project. However, understanding these settings allows you to:
- Customize them based on your specific needs
- Add additional layers of security
- Make informed decisions when deploying to production
Core Django Security Settings
Let's explore the most important security settings in Django:
SECRET_KEY
The SECRET_KEY
setting is one of the most crucial security settings in Django. It's used for:
- Cryptographic signing
- CSRF protection
- Session security
# settings.py
# Never use this in production - this is just an example
SECRET_KEY = 'django-insecure-x#j*w!b=wmf4=hr4n$qu$1_76k)qzxr4fx+9c5==a_5m^5ovhi'
Best Practices:
- Keep your secret key... well, secret!
- Use environment variables in production:
# settings.py
import os
from django.core.management.utils import get_random_secret_key
# Load from environment variable or generate a new one
SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY', get_random_secret_key())
- Never commit your actual secret key to version control.
DEBUG Mode
The DEBUG
setting controls Django's debug mode. In development, it provides helpful error pages, but in production, it can expose sensitive information:
# settings.py
# Development setting
DEBUG = True # Shows detailed error pages
# Production setting
DEBUG = False # Shows generic error pages
Best Practice: Always set DEBUG = False
in production and configure it through environment variables:
# settings.py
import os
# Read from environment variable, default to False for safety
DEBUG = os.environ.get('DJANGO_DEBUG', '').lower() == 'true'
ALLOWED_HOSTS
When DEBUG = False
, Django requires you to specify which hosts are allowed to serve your application:
# settings.py
# In development
ALLOWED_HOSTS = ['localhost', '127.0.0.1']
# In production
ALLOWED_HOSTS = ['www.yoursite.com', 'yoursite.com']
Security Implication: This prevents HTTP Host header attacks by validating the Host header in each request against this list.
CSRF Protection
Cross-Site Request Forgery (CSRF) protection is enabled by default in Django through middleware:
# settings.py
MIDDLEWARE = [
# ...
'django.middleware.csrf.CsrfViewMiddleware',
# ...
]
To use CSRF protection in your templates, include the CSRF token in your forms:
<form method="post">
{% csrf_token %}
<!-- form fields here -->
<button type="submit">Submit</button>
</form>
For AJAX requests, you need to include the CSRF token in your headers:
// JavaScript example
const csrftoken = document.querySelector('[name=csrfmiddlewaretoken]').value;
fetch('/api/endpoint/', {
method: 'POST',
headers: {
'X-CSRFToken': csrftoken,
'Content-Type': 'application/json',
},
body: JSON.stringify(data)
})
SECURE_SSL_REDIRECT
This setting forces all non-HTTPS requests to be redirected to HTTPS:
# settings.py
# In production
SECURE_SSL_REDIRECT = True
# In development
SECURE_SSL_REDIRECT = False
Best Practice: Enable this in production to enforce HTTPS.
Session Security Settings
Django provides several settings to secure your user sessions:
# settings.py
# Store session data in cookies (not in database)
SESSION_ENGINE = "django.contrib.sessions.backends.signed_cookies"
# Prevent JavaScript from accessing session cookie
SESSION_COOKIE_HTTPONLY = True
# Send cookies only via HTTPS
SESSION_COOKIE_SECURE = True
# Session expiry (in seconds)
SESSION_COOKIE_AGE = 1209600 # 2 weeks
HTTP Strict Transport Security (HSTS)
HSTS tells browsers to only access your site using HTTPS:
# settings.py
# Enable HSTS
SECURE_HSTS_SECONDS = 31536000 # 1 year
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_HSTS_PRELOAD = True
Note: Only enable HSTS when you're certain your site is properly configured for HTTPS, as it can make your site inaccessible if HTTPS is misconfigured.
Content Security Policy
Django doesn't have built-in CSP settings, but you can implement it using the django-csp
package:
pip install django-csp
Then add it to your settings:
# settings.py
MIDDLEWARE = [
# ...
'csp.middleware.CSPMiddleware',
# ...
]
# Example CSP settings
CSP_DEFAULT_SRC = ("'self'",)
CSP_STYLE_SRC = ("'self'", "'unsafe-inline'", "fonts.googleapis.com")
CSP_SCRIPT_SRC = ("'self'",)
CSP_FONT_SRC = ("'self'", "fonts.gstatic.com")
CSP_IMG_SRC = ("'self'", "data:")
Practical Example: Security Settings for a Production Django Application
Let's see how we can combine these settings in a production environment:
# production_settings.py
import os
from pathlib import Path
BASE_DIR = Path(__file__).resolve().parent.parent
# Security settings
SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY')
DEBUG = False
ALLOWED_HOSTS = [os.environ.get('DJANGO_ALLOWED_HOST')]
# HTTPS settings
SECURE_SSL_REDIRECT = True
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
# Session settings
SESSION_COOKIE_SECURE = True
SESSION_COOKIE_HTTPONLY = True
CSRF_COOKIE_SECURE = True
CSRF_COOKIE_HTTPONLY = True
# HSTS settings
SECURE_HSTS_SECONDS = 31536000
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_HSTS_PRELOAD = True
# Content security policy
MIDDLEWARE = [
# ... other middleware
'csp.middleware.CSPMiddleware',
]
CSP_DEFAULT_SRC = ("'self'",)
CSP_STYLE_SRC = ("'self'", "fonts.googleapis.com")
CSP_FONT_SRC = ("'self'", "fonts.gstatic.com")
Testing Your Security Settings
Django provides a convenient way to check if your security settings are properly configured:
python manage.py check --deploy
This command will analyze your settings and provide recommendations for improving security.
Security Settings for Development vs. Production
It's a good practice to have separate settings for development and production environments:
# settings.py
# Base settings here...
if os.environ.get('DJANGO_ENV') == 'production':
from .production_settings import *
else:
from .development_settings import *
In your development_settings.py
:
# development_settings.py
DEBUG = True
SECRET_KEY = 'dev-secret-key-for-local-use-only'
ALLOWED_HOSTS = ['localhost', '127.0.0.1']
# Disable production-only security features
SECURE_SSL_REDIRECT = False
SESSION_COOKIE_SECURE = False
CSRF_COOKIE_SECURE = False
SECURE_HSTS_SECONDS = 0
Summary
In this tutorial, we've covered Django's essential security settings:
- SECRET_KEY: Keep it secret and use environment variables
- DEBUG: Turn it off in production
- ALLOWED_HOSTS: Restrict which hosts can serve your application
- CSRF Protection: Enabled by default through middleware
- HTTPS Settings: Force HTTPS with settings like
SECURE_SSL_REDIRECT
- Session Security: Configure cookies for enhanced security
- HSTS: Tell browsers to only use HTTPS
- Content Security Policy: Add an extra layer of protection against XSS attacks
Properly configuring these settings will significantly improve your Django application's security posture.
Additional Resources
- Django Security Documentation
- Django Security Checklist
- OWASP Top Ten Project - Common web application security risks
- Mozilla Web Security - Additional web security best practices
Exercises
- Run the
python manage.py check --deploy
command on your current Django project and address at least three security issues it identifies. - Create a strategy for storing your Django secret key as an environment variable in your development and production environments.
- Implement a Content Security Policy for your Django application using the
django-csp
package. - Set up separate development and production settings files for one of your Django projects.
By implementing these security settings and following best practices, you'll build Django applications that are more resistant to common web security threats.
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)