SECRET_KEY
ProperlyA strong and unique SECRET_KEY
is critical for security. Avoid hardcoding it in settings.py
. Instead, store it in environment variables:
import os
SECRET_KEY = os.getenv("DJANGO_SECRET_KEY")
Generate a strong key using:
python -c 'import secrets; print(secrets.token_urlsafe(50))'
In production, set this in your environment variables or a .env
file.
Debug mode (DEBUG = True
) exposes sensitive information in error messages. Disable it in production:
DEBUG = False
Also, set ALLOWED_HOSTS
to restrict access:
ALLOWED_HOSTS = ['yourdomain.com']
Never store database credentials directly in settings.py
. Instead, use environment variables:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': os.getenv('DB_NAME'),
'USER': os.getenv('DB_USER'),
'PASSWORD': os.getenv('DB_PASSWORD'),
'HOST': os.getenv('DB_HOST'),
'PORT': os.getenv('DB_PORT'),
}
}
Use strong passwords and limit database user permissions.
Always enable HTTPS to encrypt communication:
SECURE_SSL_REDIRECT = True
to force HTTPS.SECURE_HSTS_SECONDS = 31536000 # 1 year
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_HSTS_PRELOAD = True
Django automatically escapes HTML in templates, but never trust user input.
Use safe
carefully in templates:
{# Avoid unless necessary #}
Use Django’s built-in bleach
library for sanitizing input:
from bleach.sanitizer import Cleaner
cleaner = Cleaner(tags=['b', 'i', 'u', 'a'], attributes={'a': ['href']})
safe_text = cleaner.clean(user_input)
Always use Django’s ORM instead of raw SQL:
User.objects.filter(email=email).first() # Safe
If raw queries are necessary, use parameterized queries:
cursor.execute("SELECT * FROM users WHERE email = %s", [email]) # Safe
Never concatenate user input directly into queries.
Django includes CSRF protection by default. Ensure all forms include a CSRF token:
<form method="post">
{% endraw %}{% csrf_token %}
</form>
For APIs, use csrf_exempt
only when necessary and consider token-based authentication instead.
from django.views.decorators.csrf import csrf_exempt
@csrf_exempt
def my_api_view(request):
...
AUTH_PASSWORD_VALIDATORS
:AUTH_PASSWORD_VALIDATORS = [
{'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 'OPTIONS': {'min_length': 8}},
{'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator'},
{'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator'},
]
LOGIN_URL
and LOGIN_REDIRECT_URL
properly.django-otp
or django-two-factor-auth
.To prevent brute-force attacks, use django-axes
or Django’s built-in authentication middleware:
pip install django-axes
Add it to INSTALLED_APPS
:
INSTALLED_APPS = [
'axes',
...
]
Add middleware:
MIDDLEWARE = [
'axes.middleware.AxesMiddleware',
...
]
Run migrations:
python manage.py migrate axes
This limits failed login attempts based on IP or user.
MEDIA_ROOT
and serve them securely.FileExtensionValidator
:from django.core.validators import FileExtensionValidator
from django.db import models
class Profile(models.Model):
avatar = models.ImageField(upload_to='avatars/', validators=[FileExtensionValidator(['jpg', 'png'])])
Use CONTENT_LENGTH
limits in nginx
or Django settings to prevent large file uploads.
Django’s SecurityMiddleware
adds protections against common attacks. Ensure it’s enabled:
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
...
]
It enforces:
If exposing APIs:
django-cors-headers
:pip install django-cors-headers
INSTALLED_APPS = [
'corsheaders',
...
]
MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware',
...
]
CORS_ALLOWED_ORIGINS = [
"https://example.com",
]
pip install django-ratelimit
from django_ratelimit.decorators import ratelimit
@ratelimit(key='ip', rate='5/m')
def my_api_view(request):
...
Django’s logging can help detect suspicious activity:
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'file': {
'level': 'WARNING',
'class': 'logging.FileHandler',
'filename': 'security.log',
},
},
'loggers': {
'django.security': {
'handlers': ['file'],
'level': 'WARNING',
'propagate': True,
},
},
}
This logs security-related warnings and errors to security.log
.
Outdated dependencies introduce vulnerabilities. Use:
pip list --outdated
Upgrade dependencies:
pip install --upgrade -r requirements.txt
Automate security checks using:
pip install safety
safety check
/admin/
URL:urlpatterns = [
path('secure-admin/', admin.site.urls),
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
...
]
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
ALLOWED_HOSTS = ['yourdomain.com']