security & Best Practices
Learn Django's built-in security features and best practices to protect your web applications from vulnerabilities.
55 min•By Priygop Team•Last updated: Feb 2026
Django security Features
Django includes many built-in security features to protect your applications from common web vulnerabilities. Understanding these features is essential for building secure applications.
security Best Practices
Example
# settings.py - security Settings
import os
from pathlib import Path
# security settings
SECRET_KEY = os.environ.get('SECRET_KEY', 'your-secret-key-here')
# HTTPS settings
SECURE_SSL_REDIRECT = True # Redirect HTTP to HTTPS
SECURE_HSTS_SECONDS = 31536000 # 1 year
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_HSTS_PRELOAD = True
# Cookie settings
SESSION_COOKIE_SECURE = True # Only send cookies over HTTPS
CSRF_COOKIE_SECURE = True
SESSION_COOKIE_HTTPONLY = True # Prevent XSS
CSRF_COOKIE_HTTPONLY = True
# Content security Policy
CSP_DEFAULT_SRC = ("'self'",)
CSP_STYLE_SRC = ("'self'", "'unsafe-inline'")
CSP_SCRIPT_SRC = ("'self'",)
# CSRF Protection
CSRF_TRUSTED_ORIGINS = [
'https://yourdomain.com',
'https://www.yourdomain.com',
]
# XSS Protection
SECURE_BROWSER_XSS_FILTER = True
SECURE_CONTENT_TYPE_NOSNIFF = True
# Clickjacking Protection
X_FRAME_OPTIONS = 'DENY'
# SQL Injection Protection (Django ORM handles this automatically)
# Always use Django ORM instead of raw SQL when possible
# Example of secure form handling
from django.views.decorators.csrf import csrf_protect
from django.views.decorators.http import require_http_methods
@csrf_protect
@require_http_methods(["GET", "POST"])
def secure_form(request):
if request.method == 'POST':
form = MyForm(request.POST)
if form.is_valid():
# Process form data
pass
else:
form = MyForm()
return render(request, 'form.html', {'form': form})
# Rate limiting
from django.core.cache import cache
from django.http import HttpResponseTooManyRequests
def rate_limit(view_func):
def wrapper(request, *args, **kwargs):
# Get client IP
client_ip = request.META.get('REMOTE_ADDR')
# Check rate limit
cache_key = f'rate_limit_{client_ip}'
request_count = cache.get(cache_key, 0)
if request_count > 100: # 100 requests per hour
return HttpResponseTooManyRequests('Rate limit exceeded')
# Increment counter
cache.set(cache_key, request_count + 1, 3600) # 1 hour
return view_func(request, *args, **kwargs)
return wrapper
# Input validation
from django.core.validators import validate_email
from django.core.exceptions import ValidationError
def validate_user_input(data):
errors = {}
# Email validation
try:
validate_email(data.get('email', ''))
except ValidationError:
errors['email'] = 'Enter a valid email address.'
# Password strength
password = data.get('password', '')
if len(password) < 8:
errors['password'] = 'Password must be at least 8 characters long.'
elif not any(c.isupper() for c in password):
errors['password'] = 'Password must contain at least one uppercase letter.'
elif not any(c.isdigit() for c in password):
errors['password'] = 'Password must contain at least one number.'
return errors
# File upload security
import os
from django.core.files.storage import default_storage
def secure_file_upload(file):
# Check file size
if file.size > 5 * 1024 * 1024: # 5MB
raise ValidationError('File size must be under 5MB.')
# Check file extension
allowed_extensions = ['.jpg', '.jpeg', '.png', '.gif', '.pdf']
file_extension = os.path.splitext(file.name)[1].lower()
if file_extension not in allowed_extensions:
raise ValidationError('File type not allowed.')
# Generate secure filename
import uuid
secure_filename = f"{uuid.uuid4()}{file_extension}"
# Save file securely
file_path = default_storage.save(f'uploads/{secure_filename}', file)
return file_path
# SQL Injection Prevention
# ❌ Bad - Don't do this
def bad_query(request):
user_input = request.GET.get('search', '')
query = f"SELECT * FROM posts WHERE title LIKE '%{user_input}%'"
# This is vulnerable to SQL injection
# ✅ Good - Use Django ORM
def good_query(request):
user_input = request.GET.get('search', '')
posts = Post.objects.filter(title__icontains=user_input)
# Django ORM automatically escapes user input
# XSS Prevention
# Django templates automatically escape HTML
# {{ user_input }} # Safe - automatically escaped
# {{ user_input|safe }} # Dangerous - only use with trusted content
# CSRF Protection
# Django includes CSRF protection by default
# Include {% csrf_token %} in all forms
# Password hashing
from django.contrib.auth.hashers import make_password, check_password
# Hash password
hashed_password = make_password('my_password')
# Check password
is_valid = check_password('my_password', hashed_password)