| name | django-security |
| description | Django security best practices for authentication, authorization, CSRF, SQL injection, and XSS prevention. Use when hardening Django apps, reviewing Django security settings, or configuring secure deployments. |
| origin | MCC |
Django Security Best Practices
Comprehensive security guidelines for Django applications.
When to Activate
- Setting up Django authentication and authorization
- Implementing user permissions and roles
- Configuring production security settings
- Reviewing Django application for security issues
- Deploying Django applications to production
Core Security Settings
Production Settings
import os
DEBUG = False
ALLOWED_HOSTS = os.environ.get('ALLOWED_HOSTS', '').split(',')
SECURE_SSL_REDIRECT = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
SECURE_HSTS_SECONDS = 31536000
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_HSTS_PRELOAD = True
SECURE_CONTENT_TYPE_NOSNIFF = True
SECURE_BROWSER_XSS_FILTER = True
X_FRAME_OPTIONS = 'DENY'
SESSION_COOKIE_HTTPONLY = True
CSRF_COOKIE_HTTPONLY = True
SESSION_COOKIE_SAMESITE = 'Lax'
CSRF_COOKIE_SAMESITE = 'Lax'
SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY')
if not SECRET_KEY:
raise ImproperlyConfigured('DJANGO_SECRET_KEY environment variable is required')
Password Hashing
PASSWORD_HASHERS = [
'django.contrib.auth.hashers.Argon2PasswordHasher',
'django.contrib.auth.hashers.PBKDF2PasswordHasher',
'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher',
'django.contrib.auth.hashers.BCryptSHA256PasswordHasher',
]
Authentication
Custom User Model
from django.contrib.auth.models import AbstractUser
from django.db import models
class User(AbstractUser):
email = models.EmailField(unique=True)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username']
AUTH_USER_MODEL = 'users.User'
Always define a custom user model at project start. Changing later requires complex migrations.
Authorization
Permissions with LoginRequired
from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin
from django.views.generic import UpdateView
class PostUpdateView(LoginRequiredMixin, PermissionRequiredMixin, UpdateView):
model = Post
permission_required = 'app.can_edit_others'
raise_exception = True
def get_queryset(self):
return Post.objects.filter(author=self.request.user)
DRF Custom Permissions
from rest_framework import permissions
class IsOwnerOrReadOnly(permissions.BasePermission):
def has_object_permission(self, request, view, obj):
if request.method in permissions.SAFE_METHODS:
return True
return obj.author == request.user
SQL Injection Prevention
User.objects.get(username=username)
User.objects.filter(Q(username__icontains=query) | Q(email__icontains=query))
User.objects.raw('SELECT * FROM users WHERE username = %s', [query])
User.objects.raw(f'SELECT * FROM users WHERE username = {username}')
XSS Prevention
{# Django auto-escapes by default — SAFE #}
{{ user_input }}
{# Only mark trusted content as safe #}
{{ trusted_html|safe }}
{# JavaScript escaping #}
<script>var username = {{ username|escapejs }};</script>
from django.utils.html import format_html, escape
def greet_user(username):
return format_html('<span class="user">{}</span>', escape(username))
CSRF Protection
CSRF is enabled by default. Key settings:
CSRF_COOKIE_SECURE = True
CSRF_COOKIE_HTTPONLY = True
CSRF_TRUSTED_ORIGINS = ['https://example.com']
In templates: {% csrf_token %} in every POST form. For AJAX: send X-CSRFToken header.
API Security
Rate Limiting (DRF)
REST_FRAMEWORK = {
'DEFAULT_THROTTLE_CLASSES': [
'rest_framework.throttling.AnonRateThrottle',
'rest_framework.throttling.UserRateThrottle'
],
'DEFAULT_THROTTLE_RATES': {
'anon': '100/day',
'user': '1000/day',
}
}
Authentication Classes
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.TokenAuthentication',
'rest_framework_simplejwt.authentication.JWTAuthentication',
],
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
],
}
Environment Variables
import environ
env = environ.Env(DEBUG=(bool, False))
environ.Env.read_env()
SECRET_KEY = env('DJANGO_SECRET_KEY')
DATABASE_URL = env('DATABASE_URL')
ALLOWED_HOSTS = env.list('ALLOWED_HOSTS')
Never commit .env files.
Quick Security Checklist
| Check | Description |
|---|
DEBUG = False | Never use True in production |
| HTTPS only | Force SSL, secure cookies |
| Strong secrets | Use environment variables for SECRET_KEY |
| Password validation | Enable all password validators |
| CSRF protection | Enabled by default, don't disable |
| XSS prevention | Auto-escaping on, don't use ` |
| SQL injection | Use ORM, never concatenate strings in queries |
| File uploads | Validate file type and size |
| Rate limiting | Throttle API endpoints |
| Security headers | CSP, X-Frame-Options, HSTS |
| Logging | Log security events |
| Updates | Keep Django and dependencies updated |
Reference Files
Remember: Security is a process, not a product. Regularly review and update your security practices.