This checklist covers Django-specific security configurations, Python best practices, and Heroku deployment security for Django applications.
Expedited WAF for Django
Expedited WAF adds network level request filtering, preventing malicious attacks from ever touching your application. This enables true defense in depth for your Django app—even if your framework has a vulnerability or is improperly configured, Expedited WAF dynamically blocks threats before they reach your code.
From experience, we’ve seen many applications where attacks technically didn’t succeed, but burned through so many server resources that the application went down anyway. By filtering malicious requests at the network edge, Expedited WAF protects both your security and your availability.
New Security Features for Your Django App
These capabilities aren’t available out of the box with Django, but Expedited WAF adds them instantly:
- Block IP Addresses - Stop malicious actors by IP or CIDR range
- Block User Agents - Filter out bad bots and scrapers
- Block by Geolocation - Restrict traffic by country or region
- DDoS Protection - Stop attacks with CAPTCHA challenges
- Block Anonymous Proxies - Prevent traffic from VPNs and proxy networks
Django Framework Security
-
Set DEBUG = False in production
- Never deploy with
DEBUG = True - Configure
DEBUG = os.environ.get('DEBUG', 'False') == 'True' - Verify with
heroku config:get DEBUG
- Never deploy with
-
Configure SECRET_KEY securely
- Store in Heroku config vars:
heroku config:set SECRET_KEY='your-secret-key' - Never commit to version control
- Use cryptographically strong random string (50+ characters)
- Rotate periodically
- Store in Heroku config vars:
-
Set ALLOWED_HOSTS properly
- Add your Heroku app domain:
['yourapp.herokuapp.com'] - Include custom domains if configured
- Never use
ALLOWED_HOSTS = ['*']in production
- Add your Heroku app domain:
-
Enable CSRF protection
- Ensure
django.middleware.csrf.CsrfViewMiddlewareis enabled - Use
{% csrf_token %}in all forms - Configure
CSRF_COOKIE_SECURE = Truefor HTTPS - Set
CSRF_COOKIE_HTTPONLY = True
- Ensure
-
Configure secure session cookies
SESSION_COOKIE_SECURE = True # HTTPS only SESSION_COOKIE_HTTPONLY = True # No JavaScript access SESSION_COOKIE_SAMESITE = 'Strict' SESSION_COOKIE_AGE = 1209600 # 2 weeks max -
Enable XSS protection middleware
SecurityMiddlewareshould be first in MIDDLEWARE- Set
SECURE_BROWSER_XSS_FILTER = True - Set
SECURE_CONTENT_TYPE_NOSNIFF = True
-
Configure HTTPS/SSL settings
SECURE_SSL_REDIRECT = True SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https') SECURE_HSTS_SECONDS = 31536000 # 1 year SECURE_HSTS_INCLUDE_SUBDOMAINS = True SECURE_HSTS_PRELOAD = True -
Implement Content Security Policy (CSP)
- Install django-csp:
pip install django-csp - Configure restrictive CSP headers
- Test with report-only mode first
- Install django-csp:
-
Disable clickjacking
- Ensure
XFrameOptionsMiddlewareis enabled - Set
X_FRAME_OPTIONS = 'DENY'
- Ensure
Database Security
-
Use Heroku Postgres with SSL
- Configure
DATABASESto require SSL:
DATABASES['default'] = dj_database_url.config( conn_max_age=600, ssl_require=True ) - Configure
-
Never log SQL queries in production
- Set appropriate logging levels
- Disable Django Debug Toolbar in production
-
Use parameterized queries
- Always use Django ORM or parameterized raw queries
- Never string concatenation for SQL
-
Implement database connection pooling
- Set
conn_max_age=600for persistent connections - Monitor connection usage
- Set
Authentication & Authorization
-
Use Django’s authentication system
- Don’t roll your own authentication
- Use
django.contrib.auth
-
Enforce strong password requirements
AUTH_PASSWORD_VALIDATORS = [ {'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator'}, {'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 'OPTIONS': {'min_length': 12}}, {'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator'}, {'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator'}, ] -
Implement rate limiting
- Install django-ratelimit:
pip install django-ratelimit - Apply to login, password reset, API endpoints
- How to Block User Agents on Heroku
- Install django-ratelimit:
-
Use Django’s permission system
- Implement proper
@permission_requireddecorators - Use
LoginRequiredMixinfor class-based views - Never rely on client-side authorization
- Implement proper
-
Configure password reset security
- Set short token expiration:
PASSWORD_RESET_TIMEOUT = 3600# 1 hour - Use HTTPS for reset emails
- Set short token expiration:
Static Files & Media
-
Serve static files securely
- Use WhiteNoise for static files:
pip install whitenoise - Configure in settings:
MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'whitenoise.middleware.WhiteNoiseMiddleware', # ... ] STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage' - Use WhiteNoise for static files:
-
Store media files on S3/external storage
- Never store uploads on Heroku’s ephemeral filesystem
- Use django-storages with S3
- Validate file uploads (type, size, content)
-
Sanitize user uploads
- Validate file extensions and MIME types
- Scan for malware if possible
- Generate unique filenames
- Set appropriate permissions
Python Dependencies
-
Pin all dependency versions
- Use
requirements.txtwith exact versions - Run
pip freeze > requirements.txt - Review dependencies before updating
- Use
-
Scan for vulnerabilities
- Use
pip-auditorsafety:pip install pip-audit - Run
pip-auditin CI/CD pipeline - Keep dependencies updated
- Use
-
Remove unused dependencies
- Minimize attack surface
- Use
pipdeptreeto identify unused packages
Environment Variables & Secrets
-
Store all secrets in Heroku config vars
heroku config:set SECRET_KEY='...' heroku config:set DATABASE_URL='...' heroku config:set AWS_ACCESS_KEY_ID='...' -
Never commit secrets to Git
- Use
.gitignorefor local.envfiles - Use
python-decouplefor local development - Audit commits for leaked secrets
- Use
-
Rotate credentials regularly
- Database passwords
- API keys
- SECRET_KEY
Logging & Monitoring
-
Configure structured logging
LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'handlers': { 'console': { 'class': 'logging.StreamHandler', }, }, 'root': { 'handlers': ['console'], 'level': 'INFO', }, } -
Log security events
- Failed login attempts
- Permission denials
- Suspicious activity
-
Never log sensitive data
- Passwords
- API keys
- Personal information
- Credit card numbers
-
Monitor application metrics
- Set up Heroku application metrics
- Configure alerts for anomalies
- Monitor error rates
Heroku Deployment
-
Configure Heroku runtime
- Specify Python version in
runtime.txt - Use supported Python versions only
- Keep runtime updated
- Specify Python version in
-
Use Procfile best practices
web: gunicorn myproject.wsgi --log-file -- Use production WSGI server (Gunicorn, uWSGI)
- Configure appropriate workers
- Enable access logs
API Security (Django REST Framework)
-
Implement authentication
- Use Token or JWT authentication
- Never rely on session auth for public APIs
- Rotate tokens regularly
-
Configure throttling
REST_FRAMEWORK = { 'DEFAULT_THROTTLE_CLASSES': [ 'rest_framework.throttling.AnonRateThrottle', 'rest_framework.throttling.UserRateThrottle' ], 'DEFAULT_THROTTLE_RATES': { 'anon': '100/hour', 'user': '1000/hour' } } -
Validate all input
- Use serializers for validation
- Never trust client input
- Sanitize output
-
Implement CORS properly
- Install django-cors-headers
- Configure allowed origins explicitly
- Never use
CORS_ORIGIN_ALLOW_ALL = True
Compliance & Best Practices
-
Run Django’s security check
python manage.py check --deploy- Fix all warnings before deployment
-
Implement GDPR compliance
- Data retention policies
- User data export/deletion
- Privacy policy
- Cookie consent
-
Regular security audits
- Code reviews
- Dependency audits
- Penetration testing
-
Keep Django updated
- Subscribe to security mailing list
- Apply security patches promptly
- Test updates in staging first
Testing
-
Write security tests
- Test authentication/authorization
- Test CSRF protection
- Test input validation
- Test permission boundaries
-
Test on Heroku staging environment
- Create staging app:
heroku create myapp-staging - Test all security configurations
- Verify HTTPS enforcement
- Create staging app: