Security essentials for Django — CSRF, CORS, security middleware, ALLOWED_HOSTS,
99
99%
Does it follow best practices?
Impact
99%
2.91xAverage score across 2 eval scenarios
Passed
No known issues
Django has good security defaults, but they must be configured correctly for production.
Django includes these by default (don't disable them):
Your job: configure what Django can't know — hosts, secrets, CORS, HTTPS.
# settings.py
ALLOWED_HOSTS = os.environ.get('ALLOWED_HOSTS', 'localhost,127.0.0.1').split(',')Empty ALLOWED_HOSTS in production = host header attacks. Django rejects requests with unrecognized Host headers, but only if this is set.
SECRET_KEY = os.environ.get('SECRET_KEY')
if not SECRET_KEY and not DEBUG:
raise ImproperlyConfigured('Set SECRET_KEY for production')Never commit the secret key. Use env vars or a secrets manager.
pip install django-cors-headersINSTALLED_APPS = [..., 'corsheaders', ...]
MIDDLEWARE = ['corsheaders.middleware.CorsMiddleware', ...] # Must be near top
CORS_ALLOWED_ORIGINS = os.environ.get('CORS_ORIGINS', 'http://localhost:5173').split(',')
# NOT: CORS_ALLOW_ALL_ORIGINS = True# Production settings
SECURE_BROWSER_XSS_FILTER = True
SECURE_CONTENT_TYPE_NOSNIFF = True
SESSION_COOKIE_SECURE = True # HTTPS only
SESSION_COOKIE_HTTPONLY = True # Prevent JavaScript access to session cookie
CSRF_COOKIE_SECURE = True # HTTPS only
SECURE_SSL_REDIRECT = True # Redirect HTTP to HTTPS
SECURE_HSTS_SECONDS = 31536000 # 1 year HSTS
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
X_FRAME_OPTIONS = 'DENY'
# CSRF trusted origins — required when your frontend is on a different domain
CSRF_TRUSTED_ORIGINS = os.environ.get('CSRF_TRUSTED_ORIGINS', 'https://yourdomain.com').split(',')For development, these should be False/0. Use separate settings or environment checks.
Always set CSRF_TRUSTED_ORIGINS when deploying behind a reverse proxy or when the frontend origin differs from the backend. Django 4.0+ requires this for cross-origin POST requests to succeed.
For API-only backends (DRF with token auth), CSRF can be disabled on specific views:
from django.views.decorators.csrf import csrf_exempt
# Only exempt API views that use token authentication, not session authBut if using session-based auth, keep CSRF enabled and include the token in API requests:
// Frontend: read CSRF token from cookie
const csrfToken = document.cookie.match(/csrftoken=([^;]+)/)?.[1];
fetch('/api/orders', {
method: 'POST',
headers: { 'X-CSRFToken': csrfToken, 'Content-Type': 'application/json' },
body: JSON.stringify(data),
});Django has a built-in security checker:
python manage.py check --deployThis warns about missing security settings. Run it before every deployment.
ALLOWED_HOSTS set from environment (not ['*'])SECRET_KEY from environment, not in settings.pyDEBUG = False in productiondjango-cors-headers with explicit originsCSRF_TRUSTED_ORIGINS set from environment or explicit listSESSION_COOKIE_SECURE = True and SESSION_COOKIE_HTTPONLY = Truepython manage.py check --deploy passesCORS_ALLOW_ALL_ORIGINS = True in production