guide

SaaS Security Checklist for Django Applications

Complete security checklist for Django SaaS: authentication, data encryption, API security, GDPR compliance, penetration testing. 47-point checklist with implementation details. From EUR 3,000.

TL;DR

A security breach costs the average SaaS company EUR 150,000 in direct costs (incident response, legal, notification) plus 20-40% customer churn. Django provides strong security defaults, but SaaS applications require additional hardening across authentication, data isolation, API security, encryption, and compliance. This 47-point checklist covers every layer, with specific Django settings, package recommendations, and implementation costs (EUR 3,000-8,000 for a full security audit and hardening).

Authentication and Authorisation: Beyond Django Defaults

Django's built-in authentication is solid but insufficient for production SaaS. Here are the critical additions required.

Password security:

  • Argon2 hashing: Switch from Django's default PBKDF2 to Argon2id — the winner of the Password Hashing Competition. PASSWORD_HASHERS = ["django.contrib.auth.hashers.Argon2PasswordHasher", ...]. Install argon2-cffi. Argon2id is resistant to both GPU and side-channel attacks.
  • Password validation: Enable all Django validators plus add django-password-validators for breach database checking (checks against Have I Been Pwned's 800M+ compromised passwords via k-anonymity API — no password leaves your server).
  • Rate limiting: django-axes — locks out IP after 5 failed login attempts for 30 minutes. Configurable per-user and per-IP lockout. Essential to prevent credential stuffing attacks. AXES_FAILURE_LIMIT = 5, AXES_COOLOFF_TIME = timedelta(minutes=30).

Multi-factor authentication (MFA):

  • Use django-allauth with TOTP (Time-based One-Time Password) support. Users scan a QR code with Google Authenticator, Authy, or 1Password.
  • Enforce MFA for admin users and optionally for all users. Store recovery codes (10 single-use codes generated at MFA setup).
  • WebAuthn/FIDO2 support via django-fido2 for hardware security keys (YubiKey). Phishing-resistant authentication.
  • Implementation cost: EUR 800-1,500 for TOTP MFA. EUR 1,500-2,500 for TOTP + WebAuthn.

Session security:

  • SESSION_COOKIE_SECURE = True (HTTPS only)
  • SESSION_COOKIE_HTTPONLY = True (no JavaScript access)
  • SESSION_COOKIE_SAMESITE = "Lax" (CSRF protection)
  • SESSION_COOKIE_AGE = 86400 (24-hour session timeout for SaaS)
  • Implement session invalidation on password change: update_session_auth_hash(request, user)
  • Track active sessions: store IP, user agent, last activity. Allow users to revoke sessions from settings page ("Logged in on: Chrome, Berlin — 2 hours ago").

Role-based access control (RBAC):

  • Use django-guardian for object-level permissions or django-rules for predicate-based permissions.
  • Typical SaaS roles: Owner (full access + billing), Admin (team + settings management), Member (standard access), Viewer (read-only), Guest (limited access to shared items).
  • Implement permission checks in DRF views: class ProjectViewSet: permission_classes = [IsAuthenticated, HasProjectAccess]. Never rely solely on frontend hiding UI elements — always enforce on backend.

Data Protection: Encryption, Backups, and GDPR

SaaS applications store sensitive customer data. Encryption and data protection are non-negotiable — both for security and legal compliance under GDPR.

Encryption at rest:

  • Database encryption: Use PostgreSQL Transparent Data Encryption (TDE) or encrypted storage volumes (AWS EBS encryption, Hetzner encrypted volumes). All data on disk is encrypted with AES-256.
  • Field-level encryption: For highly sensitive fields (API keys, PII, financial data), use django-encrypted-model-fields or django-fernet-fields. Encrypt individual model fields with Fernet symmetric encryption. api_key = encrypt(models.CharField(max_length=255)). Data is encrypted before database write and decrypted on read.
  • File encryption: User-uploaded files in S3: enable server-side encryption (SSE-S3 or SSE-KMS). For maximum security, encrypt client-side before upload using AWS KMS or a tenant-specific encryption key.

Encryption in transit:

  • TLS 1.2+ on all connections. Configure Nginx/Caddy with HSTS header: Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
  • Database connections: DATABASES["default"]["OPTIONS"] = {"sslmode": "verify-full", "sslrootcert": "/path/to/ca.pem"}
  • Redis connections: rediss:// URL scheme for TLS-encrypted Redis connections.
  • Internal service communication: mTLS between application servers and backend services.

Backup strategy:

  • Automated daily PostgreSQL backups with pg_dump or managed database snapshots. Retain 30 daily + 12 monthly backups.
  • Test restore procedure monthly — a backup that cannot be restored is not a backup.
  • Store backups in a different region/provider than production (disaster recovery). Encrypt backup files with GPG or AES-256 before upload.
  • Recovery Time Objective (RTO): 1-4 hours. Recovery Point Objective (RPO): 24 hours for daily backups, 1 hour with WAL archiving.

GDPR compliance checklist for SaaS:

  • Data Processing Agreement (DPA): Provide a DPA to all customers. Use a standard template (available from IAPP or your legal counsel).
  • Data export: Users can request all their data in machine-readable format (JSON/CSV). Implement as a self-service feature or admin management command. Must respond within 30 days.
  • Data deletion: Right to erasure. When a user requests deletion, anonymise or delete all PII within 30 days. Implement User.anonymise() method that replaces name, email, IP addresses with anonymised values while preserving aggregate data for analytics.
  • Privacy policy: Clear, specific privacy policy explaining what data is collected, why, how long it is retained, and who has access. Update whenever processing activities change.
  • Cookie consent: Implement cookie consent banner for EU users. Only set non-essential cookies (analytics, marketing) after explicit consent.
  • Data breach notification: Process to notify supervisory authority within 72 hours and affected users without undue delay. Document the incident response plan before you need it.

API Security: Protecting Your Django REST Framework Endpoints

APIs are the primary attack surface of modern SaaS applications. Django REST Framework provides good defaults, but SaaS APIs need additional hardening.

Authentication for APIs:

  • JWT tokens: Use djangorestframework-simplejwt. Short-lived access tokens (15 minutes) + long-lived refresh tokens (7 days, rotated on use). Store refresh tokens in httpOnly cookies, access tokens in memory (not localStorage — vulnerable to XSS).
  • API keys: For machine-to-machine integrations. Generate with secrets.token_urlsafe(32). Store hashed (SHA-256) in database, show plaintext only once at creation. Implement key rotation without downtime — allow 2 active keys per tenant.
  • OAuth2: For third-party integrations. Use django-oauth-toolkit. Implement authorization code flow with PKCE for public clients.

Rate limiting:

  • DRF throttling: DEFAULT_THROTTLE_RATES = {"anon": "20/minute", "user": "100/minute", "burst": "10/second"}. Apply per-tenant limits for multi-tenant APIs.
  • For granular control: django-ratelimit with Redis backend. Rate limit by user, IP, API key, or custom key. @ratelimit(key="user", rate="100/h", method="POST")
  • Return 429 Too Many Requests with Retry-After header. Include rate limit headers in all responses: X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset.

Input validation and injection prevention:

  • Django ORM prevents SQL injection by default (parameterised queries). Never use raw() or extra() with user input. If you must use raw SQL, always use parameterised queries: cursor.execute("SELECT * FROM t WHERE id = %s", [user_input]).
  • DRF serializers validate input types and constraints. Add custom validators for business logic. Always validate on the backend — never trust frontend validation.
  • File upload validation: Check MIME type (not just extension), enforce size limits, scan for malware with ClamAV. Store uploads outside the web root — never in a directory served by Nginx.
  • XSS prevention: Django templates auto-escape by default. For APIs returning HTML content, sanitise with bleach: bleach.clean(user_html, tags=["p", "strong", "em", "ul", "li"], strip=True).

CORS configuration:

  • Use django-cors-headers. CORS_ALLOWED_ORIGINS = ["https://app.yoursaas.com"] — never use CORS_ALLOW_ALL_ORIGINS = True in production.
  • Restrict allowed methods: CORS_ALLOW_METHODS = ["GET", "POST", "PUT", "PATCH", "DELETE"].
  • Restrict allowed headers: CORS_ALLOW_HEADERS = ["authorization", "content-type", "x-tenant-id"].

Security headers:

  • Configure via django-csp and middleware: Content-Security-Policy, X-Content-Type-Options: nosniff, X-Frame-Options: DENY, Referrer-Policy: strict-origin-when-cross-origin, Permissions-Policy: camera=(), microphone=(), geolocation=().

Security Monitoring and Incident Response

Prevention is essential, but detection and response are equally critical. A SaaS application without security monitoring is flying blind.

Audit logging:

  • Use django-auditlog or django-simple-history to track all model changes. Every create, update, delete is recorded with timestamp, user, IP address, and old/new values.
  • Log authentication events: successful logins, failed logins, password changes, MFA setup/disable, session creation/destruction. Use Django signals or custom middleware.
  • Log administrative actions: user role changes, tenant settings changes, data exports, data deletions. These are critical for security investigations and compliance audits.
  • Store audit logs in a separate database or append-only table (prevent tampering). Retain for minimum 12 months (GDPR) or longer for SOC 2 compliance.

Real-time monitoring:

  • Sentry: Error tracking and performance monitoring. Capture all exceptions with full context (user, tenant, request data). EUR 26/month for 100K events.
  • Application-level alerts: Monitor for suspicious patterns — multiple failed logins from same IP (brute force), unusual data export volumes (data exfiltration), API usage spike from single tenant (abuse), admin actions outside business hours.
  • Infrastructure monitoring: Uptime monitoring (UptimeRobot free tier or Better Uptime EUR 20/month). Resource monitoring (CPU, memory, disk) with alerts at 80% utilisation. Database connection count monitoring.

Dependency security:

  • pip-audit or safety — scan Python dependencies for known vulnerabilities. Run in CI/CD pipeline on every commit. Block deployments with critical vulnerabilities.
  • dependabot or renovate — automated pull requests for dependency updates. Review and merge weekly.
  • Pin all dependencies in requirements.txt with exact versions. Use pip-compile (from pip-tools) to manage the dependency tree.
  • Django security releases: subscribe to django-announce mailing list. Apply security patches within 24 hours of release.

Incident response plan:

  1. Detection (0-15 minutes): Alert triggers from monitoring system. On-call developer acknowledges.
  2. Assessment (15-60 minutes): Determine scope — what data is affected, how many tenants, attack vector.
  3. Containment (1-4 hours): Isolate affected systems, revoke compromised credentials, block attack source. Take forensic snapshots before remediation.
  4. Notification (within 72 hours): Notify supervisory authority (GDPR requirement). Notify affected customers with: what happened, what data was affected, what you are doing about it, what they should do.
  5. Recovery (1-7 days): Restore from clean backup, patch vulnerability, deploy fix, monitor for recurrence.
  6. Post-mortem (within 2 weeks): Root cause analysis, lessons learned, preventive measures implemented. Share findings with team.

Security Audit and Hardening Packages

Security Audit (EUR 3,000-5,000):

  • Full codebase security review against OWASP Top 10
  • Django settings audit (50+ security-relevant settings checked)
  • Dependency vulnerability scan
  • Authentication and authorisation flow review
  • Data isolation audit (multi-tenant security)
  • API security assessment
  • Detailed report with prioritised findings and fix recommendations
  • Timeline: 1-2 weeks

Security Hardening (EUR 5,000-8,000):

  • Everything in Security Audit, plus implementation of fixes
  • MFA implementation (TOTP)
  • Audit logging setup with django-auditlog
  • Rate limiting and brute-force protection (django-axes)
  • Security headers configuration (django-csp)
  • Encryption for sensitive fields
  • GDPR compliance features (data export, deletion, consent management)
  • Dependency update automation (Dependabot/Renovate)
  • Security monitoring alerts setup
  • Timeline: 3-5 weeks

Penetration Testing Package (EUR 4,000-7,000):

  • Black-box penetration test of application and API
  • Authenticated testing (tenant isolation verification)
  • Common attack vectors: SQL injection, XSS, CSRF, IDOR, authentication bypass, privilege escalation
  • Multi-tenant cross-tenant access testing
  • API fuzzing with automated tools (Burp Suite, OWASP ZAP)
  • Detailed findings report with proof-of-concept and remediation steps
  • Re-test after fixes are applied
  • Timeline: 2-3 weeks

Ongoing security maintenance:

  • Monthly dependency update review and patching: EUR 200-400/month
  • Quarterly security review: EUR 800-1,200/quarter
  • Annual penetration test: EUR 3,000-5,000/year

Security tools cost (monthly):

  • Sentry (error monitoring): EUR 26/month
  • Uptime monitoring: EUR 0-20/month
  • Vulnerability scanning: EUR 0-50/month (pip-audit is free, Snyk free tier available)
  • Total security tooling: EUR 30-100/month

Frequently Asked Questions

Is Django secure enough for SaaS applications handling sensitive data?

Django is one of the most security-conscious web frameworks available. It provides built-in protection against SQL injection, XSS, CSRF, and clickjacking out of the box. The Django security team has an excellent track record of rapid vulnerability disclosure and patching. For SaaS handling sensitive data, Django needs additional hardening (MFA, field encryption, audit logging, RLS) — but the foundation is exceptionally strong. Government agencies, financial institutions, and healthcare companies use Django in production.

How often should I conduct security audits?

For a SaaS application processing customer data: full security audit at launch, then annually. Penetration testing annually or after major feature releases. Dependency vulnerability scanning on every deployment (automated in CI/CD). Code security review for every pull request touching authentication, authorisation, or data access patterns. GDPR compliance review annually or whenever data processing activities change.

What is the minimum security investment for a SaaS MVP?

At minimum, invest EUR 1,500-3,000 in security during MVP development. This covers: Django security settings hardening (1 day), rate limiting with django-axes (half day), HTTPS with proper headers (half day), basic audit logging (1 day), password hashing upgrade to Argon2 (1 hour), input validation review (1 day), and GDPR basics — privacy policy, data export, account deletion (2-3 days). Skip MFA and penetration testing for MVP — add them before scaling past 100 paying customers.

Secure Your Django SaaS Application

Request a security audit of your Django SaaS application. I will review your codebase, identify vulnerabilities, and provide a prioritised hardening plan with fixed pricing.

Request a Security Audit

or message directly: Telegram · Email