Django’s default settings are surprisingly insecure for production.
Let’s get your Django app ready for the real world. We’ll walk through hardening it against common threats.
First, the absolute must-do: DEBUG = False. This is not optional. When DEBUG is True, Django displays detailed error pages that reveal sensitive information like database contents, installed apps, and even your secret key. This is a goldmine for attackers.
# settings.py
DEBUG = False
Next, configure ALLOWED_HOSTS. This tells Django which host/domain names your site can serve. Leaving it empty or too broad allows attackers to impersonate your site using DNS spoofing or by setting the Host header to malicious values.
# settings.py
ALLOWED_HOSTS = ['yourdomain.com', 'www.yourdomain.com', 'localhost', '127.0.0.1']
Security middleware is crucial. Ensure django.middleware.security.SecurityMiddleware is at the top of your MIDDLEWARE setting. It enables several security enhancements.
# settings.py
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
# ... other middleware
]
SecurityMiddleware also provides SECURE_SSL_REDIRECT. Set this to True to automatically redirect all HTTP requests to HTTPS. This protects data in transit from eavesdropping. You’ll need an SSL certificate configured on your web server (like Nginx or Apache) for this to work correctly.
# settings.py
SECURE_SSL_REDIRECT = True
SESSION_COOKIE_SECURE and SESSION_COOKIE_HTTPONLY are vital for session security. Setting SESSION_COOKIE_SECURE = True ensures that session cookies are only sent over HTTPS. SESSION_COOKIE_HTTPONLY = True prevents client-side JavaScript from accessing the session cookie, mitigating cross-site scripting (XSS) attacks.
# settings.py
SESSION_COOKIE_SECURE = True
SESSION_COOKIE_HTTPONLY = True
CSRF_COOKIE_SECURE works similarly for Cross-Site Request Forgery (CSRF) tokens. Set it to True to ensure the CSRF cookie is only transmitted over HTTPS.
# settings.py
CSRF_COOKIE_SECURE = True
If you’re using django.contrib.sessions, consider disabling SESSION_ENGINE if you don’t need persistent sessions, or configure a secure backend like a database or cache. For most production apps, you’ll want to keep sessions, but be mindful of their security.
SECRET_KEY must be kept secret. Never commit it directly to your version control system. Use environment variables or a dedicated secrets management tool.
# settings.py (example using environment variable)
import os
SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY')
Consider SECURE_HSTS_SECONDS. This enables HTTP Strict Transport Security (HSTS), instructing browsers to only connect to your site using HTTPS for a specified duration. Start with a small value (e.g., 3600 for an hour) and increase it once you’re confident in your HTTPS setup.
# settings.py
SECURE_HSTS_SECONDS = 3600 # 1 hour
SECURE_CONTENT_TYPE_NOSNIFF set to True prevents browsers from MIME-sniffing a response away from the declared Content-Type. This helps mitigate XSS attacks where an attacker might trick a browser into executing downloaded content as if it were an executable file.
# settings.py
SECURE_CONTENT_TYPE_NOSNIFF = True
X_FRAME_OPTIONS controls whether your site can be embedded in an <iframe>, <frame>, <object>, or <embed>. Setting it to 'DENY' is the most secure option, preventing clickjacking attacks.
# settings.py
X_FRAME_OPTIONS = 'DENY'
Finally, keep your Django and all installed third-party app versions updated. Vulnerabilities are discovered and patched regularly. Regularly run pip list --outdated and upgrade packages.
pip list --outdated
pip install --upgrade Django
pip install --upgrade third-party-package
After implementing these, your next security concern will likely be managing user permissions and access control effectively.