mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-24 05:31:09 -05:00
- Introduced a comprehensive Secret Management Guide detailing best practices, secret classification, development setup, production management, rotation procedures, and emergency protocols. - Implemented a client-side performance monitoring script to track various metrics including page load performance, paint metrics, layout shifts, and memory usage. - Enhanced search accessibility with keyboard navigation support for search results, ensuring compliance with WCAG standards and improving user experience.
193 lines
7.1 KiB
Python
193 lines
7.1 KiB
Python
"""
|
|
Security configuration for thrillwiki project.
|
|
|
|
This module configures security headers and settings to protect against common
|
|
web vulnerabilities including XSS, clickjacking, MIME sniffing, and more.
|
|
|
|
Uses python-decouple for consistent environment variable management.
|
|
|
|
Why python-decouple?
|
|
- Already used in base.py for consistency
|
|
- Simpler API than django-environ
|
|
- Sufficient for our configuration needs
|
|
- Better separation of config from code
|
|
"""
|
|
|
|
from decouple import config
|
|
|
|
# =============================================================================
|
|
# Cloudflare Turnstile Configuration
|
|
# =============================================================================
|
|
# Turnstile is Cloudflare's CAPTCHA alternative for bot protection
|
|
# Get keys from: https://dash.cloudflare.com/?to=/:account/turnstile
|
|
|
|
TURNSTILE_SITE_KEY = config("TURNSTILE_SITE_KEY", default="")
|
|
TURNSTILE_SECRET_KEY = config("TURNSTILE_SECRET_KEY", default="")
|
|
TURNSTILE_VERIFY_URL = config(
|
|
"TURNSTILE_VERIFY_URL",
|
|
default="https://challenges.cloudflare.com/turnstile/v0/siteverify",
|
|
)
|
|
|
|
# =============================================================================
|
|
# Security Headers Configuration
|
|
# =============================================================================
|
|
|
|
# X-XSS-Protection: Enables browser's built-in XSS filter
|
|
# Note: Modern browsers are deprecating this in favor of CSP, but it's still
|
|
# useful for older browsers
|
|
SECURE_BROWSER_XSS_FILTER = config(
|
|
"SECURE_BROWSER_XSS_FILTER", default=True, cast=bool
|
|
)
|
|
|
|
# X-Content-Type-Options: Prevents MIME type sniffing attacks
|
|
# When True, adds "X-Content-Type-Options: nosniff" header
|
|
SECURE_CONTENT_TYPE_NOSNIFF = config(
|
|
"SECURE_CONTENT_TYPE_NOSNIFF", default=True, cast=bool
|
|
)
|
|
|
|
# X-Frame-Options: Protects against clickjacking attacks
|
|
# DENY = Never allow framing (most secure)
|
|
# SAMEORIGIN = Only allow framing from same origin
|
|
X_FRAME_OPTIONS = config("X_FRAME_OPTIONS", default="DENY")
|
|
|
|
# Referrer-Policy: Controls how much referrer information is sent
|
|
# strict-origin-when-cross-origin = Send full URL for same-origin,
|
|
# only origin for cross-origin, nothing for downgrade
|
|
SECURE_REFERRER_POLICY = config(
|
|
"SECURE_REFERRER_POLICY", default="strict-origin-when-cross-origin"
|
|
)
|
|
|
|
# Cross-Origin-Opener-Policy: Prevents cross-origin attacks via window references
|
|
# same-origin = Document can only be accessed by windows from same origin
|
|
SECURE_CROSS_ORIGIN_OPENER_POLICY = config(
|
|
"SECURE_CROSS_ORIGIN_OPENER_POLICY", default="same-origin"
|
|
)
|
|
|
|
# =============================================================================
|
|
# HSTS (HTTP Strict Transport Security) Configuration
|
|
# =============================================================================
|
|
|
|
# Include subdomains in HSTS policy
|
|
SECURE_HSTS_INCLUDE_SUBDOMAINS = config(
|
|
"SECURE_HSTS_INCLUDE_SUBDOMAINS", default=True, cast=bool
|
|
)
|
|
|
|
# HSTS max-age in seconds (31536000 = 1 year, recommended minimum)
|
|
SECURE_HSTS_SECONDS = config("SECURE_HSTS_SECONDS", default=31536000, cast=int)
|
|
|
|
# HSTS preload: Allow inclusion in browser preload lists
|
|
# Only enable after confirming HTTPS works properly for all subdomains
|
|
SECURE_HSTS_PRELOAD = config("SECURE_HSTS_PRELOAD", default=False, cast=bool)
|
|
|
|
# URLs exempt from SSL redirect (e.g., health checks)
|
|
# Format: comma-separated list of URL patterns
|
|
SECURE_REDIRECT_EXEMPT = config(
|
|
"SECURE_REDIRECT_EXEMPT",
|
|
default="",
|
|
cast=lambda v: [s.strip() for s in v.split(",") if s.strip()]
|
|
)
|
|
|
|
# Redirect all HTTP requests to HTTPS
|
|
SECURE_SSL_REDIRECT = config("SECURE_SSL_REDIRECT", default=False, cast=bool)
|
|
|
|
# Header used by proxy to indicate HTTPS
|
|
# Common values: ('HTTP_X_FORWARDED_PROTO', 'https')
|
|
_proxy_ssl_header = config("SECURE_PROXY_SSL_HEADER", default="")
|
|
SECURE_PROXY_SSL_HEADER = (
|
|
tuple(_proxy_ssl_header.split(",")) if _proxy_ssl_header else None
|
|
)
|
|
|
|
# =============================================================================
|
|
# Session Cookie Security
|
|
# =============================================================================
|
|
|
|
# Only send session cookie over HTTPS
|
|
SESSION_COOKIE_SECURE = config("SESSION_COOKIE_SECURE", default=False, cast=bool)
|
|
|
|
# Prevent JavaScript access to session cookie (mitigates XSS)
|
|
SESSION_COOKIE_HTTPONLY = config("SESSION_COOKIE_HTTPONLY", default=True, cast=bool)
|
|
|
|
# SameSite attribute: Protects against CSRF attacks
|
|
# Strict = Cookie only sent for same-site requests (most secure)
|
|
# Lax = Cookie sent for same-site and top-level navigations (default)
|
|
SESSION_COOKIE_SAMESITE = config("SESSION_COOKIE_SAMESITE", default="Lax")
|
|
|
|
# =============================================================================
|
|
# CSRF Cookie Security
|
|
# =============================================================================
|
|
|
|
# Only send CSRF cookie over HTTPS
|
|
CSRF_COOKIE_SECURE = config("CSRF_COOKIE_SECURE", default=False, cast=bool)
|
|
|
|
# Prevent JavaScript access to CSRF cookie
|
|
# Note: Set to False if you need to read the token via JavaScript for AJAX
|
|
CSRF_COOKIE_HTTPONLY = config("CSRF_COOKIE_HTTPONLY", default=True, cast=bool)
|
|
|
|
# SameSite attribute for CSRF cookie
|
|
CSRF_COOKIE_SAMESITE = config("CSRF_COOKIE_SAMESITE", default="Lax")
|
|
|
|
# =============================================================================
|
|
# Authentication Backends
|
|
# =============================================================================
|
|
# Order matters: Django tries each backend in order until one succeeds
|
|
|
|
AUTHENTICATION_BACKENDS = [
|
|
"django.contrib.auth.backends.ModelBackend",
|
|
"allauth.account.auth_backends.AuthenticationBackend",
|
|
]
|
|
|
|
# =============================================================================
|
|
# Password Validators
|
|
# =============================================================================
|
|
# Django's built-in password validators for security
|
|
|
|
AUTH_PASSWORD_VALIDATORS = [
|
|
{
|
|
"NAME": (
|
|
"django.contrib.auth.password_validation.UserAttributeSimilarityValidator"
|
|
),
|
|
},
|
|
{
|
|
"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
|
|
"OPTIONS": {
|
|
"min_length": config("PASSWORD_MIN_LENGTH", default=8, cast=int),
|
|
},
|
|
},
|
|
{
|
|
"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
|
|
},
|
|
{
|
|
"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
|
|
},
|
|
]
|
|
|
|
# =============================================================================
|
|
# Permissions Policy (Feature Policy successor)
|
|
# =============================================================================
|
|
# Controls which browser features can be used
|
|
|
|
PERMISSIONS_POLICY = {
|
|
"accelerometer": [],
|
|
"ambient-light-sensor": [],
|
|
"autoplay": [],
|
|
"camera": [],
|
|
"display-capture": [],
|
|
"document-domain": [],
|
|
"encrypted-media": [],
|
|
"fullscreen": ["self"],
|
|
"geolocation": ["self"], # Required for map features
|
|
"gyroscope": [],
|
|
"interest-cohort": [], # Block FLoC
|
|
"magnetometer": [],
|
|
"microphone": [],
|
|
"midi": [],
|
|
"payment": [],
|
|
"picture-in-picture": [],
|
|
"publickey-credentials-get": [],
|
|
"screen-wake-lock": [],
|
|
"sync-xhr": [],
|
|
"usb": [],
|
|
"web-share": ["self"],
|
|
"xr-spatial-tracking": [],
|
|
}
|