Django Security Checklist for Heroku

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.

Expedited WAF protects your Django app on Heroku

New Security Features for Your Django App

These capabilities aren’t available out of the box with Django, but Expedited WAF adds them instantly:

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
  • 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
  • Set ALLOWED_HOSTS properly

    • Add your Heroku app domain: ['yourapp.herokuapp.com']
    • Include custom domains if configured
    • Never use ALLOWED_HOSTS = ['*'] in production
  • Enable CSRF protection

    • Ensure django.middleware.csrf.CsrfViewMiddleware is enabled
    • Use {% csrf_token %} in all forms
    • Configure CSRF_COOKIE_SECURE = True for HTTPS
    • Set CSRF_COOKIE_HTTPONLY = True
  • 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

    • SecurityMiddleware should 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
  • Disable clickjacking

    • Ensure XFrameOptionsMiddleware is enabled
    • Set X_FRAME_OPTIONS = 'DENY'

Database Security

  • Use Heroku Postgres with SSL

    • Configure DATABASES to require SSL:
    DATABASES['default'] = dj_database_url.config(
        conn_max_age=600,
        ssl_require=True
    )
    
  • 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=600 for persistent connections
    • Monitor connection usage

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

  • Use Django’s permission system

    • Implement proper @permission_required decorators
    • Use LoginRequiredMixin for class-based views
    • Never rely on client-side authorization
  • Configure password reset security

    • Set short token expiration: PASSWORD_RESET_TIMEOUT = 3600 # 1 hour
    • Use HTTPS for reset emails

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'
    
  • 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.txt with exact versions
    • Run pip freeze > requirements.txt
    • Review dependencies before updating
  • Scan for vulnerabilities

    • Use pip-audit or safety: pip install pip-audit
    • Run pip-audit in CI/CD pipeline
    • Keep dependencies updated
  • Remove unused dependencies

    • Minimize attack surface
    • Use pipdeptree to 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 .gitignore for local .env files
    • Use python-decouple for local development
    • Audit commits for leaked secrets
  • 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
  • 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

Additional Resources