Security: fix middleware order and CSRF protection
This commit is contained in:
@@ -18,7 +18,7 @@ BASE_DIR = Path(__file__).resolve().parent.parent
|
|||||||
# Initialize environment variables
|
# Initialize environment variables
|
||||||
env = environ.Env(
|
env = environ.Env(
|
||||||
# Set casting and default values
|
# Set casting and default values
|
||||||
DEBUG=(bool, True),
|
DEBUG=(bool, False), # Security: default False
|
||||||
SECRET_KEY=(str, 'django-insecure-default-key-change-in-production'),
|
SECRET_KEY=(str, 'django-insecure-default-key-change-in-production'),
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -36,16 +36,19 @@ if env_file.exists():
|
|||||||
SECRET_KEY = env('SECRET_KEY')
|
SECRET_KEY = env('SECRET_KEY')
|
||||||
|
|
||||||
# SECURITY WARNING: don't run with debug turned on in production!
|
# SECURITY WARNING: don't run with debug turned on in production!
|
||||||
DEBUG = env('DEBUG')
|
DEBUG = env.bool('DEBUG', False)
|
||||||
|
DEBUG_TOOLBAR_ENABLED = DEBUG and env.bool('DEBUG_TOOLBAR_ENABLED', False)
|
||||||
|
|
||||||
# Allowed hosts: читаем из переменной окружения или используем wildcard для разработки
|
# Allowed hosts: читаем из переменной окружения
|
||||||
|
# В .env на проде: ALLOWED_HOSTS=mix.smaa.by,*.mix.smaa.by
|
||||||
ALLOWED_HOSTS = env.list('ALLOWED_HOSTS', default=['*'])
|
ALLOWED_HOSTS = env.list('ALLOWED_HOSTS', default=['*'])
|
||||||
|
|
||||||
# CSRF trusted origins для работы за nginx proxy
|
# CSRF configuration
|
||||||
CSRF_TRUSTED_ORIGINS = env.list('CSRF_TRUSTED_ORIGINS', default=[
|
CSRF_TRUSTED_ORIGINS = env.list('CSRF_TRUSTED_ORIGINS', default=[
|
||||||
'https://mix.smaa.by',
|
'https://mix.smaa.by',
|
||||||
'https://*.mix.smaa.by',
|
'https://*.mix.smaa.by',
|
||||||
])
|
])
|
||||||
|
CSRF_USE_SESSIONS = True # Рекомендуется для мультихостовых систем
|
||||||
|
|
||||||
|
|
||||||
# ============================================
|
# ============================================
|
||||||
@@ -93,8 +96,8 @@ TENANT_APPS = [
|
|||||||
# Объединяем для INSTALLED_APPS
|
# Объединяем для INSTALLED_APPS
|
||||||
INSTALLED_APPS = list(SHARED_APPS) + [app for app in TENANT_APPS if app not in SHARED_APPS]
|
INSTALLED_APPS = list(SHARED_APPS) + [app for app in TENANT_APPS if app not in SHARED_APPS]
|
||||||
|
|
||||||
# Django Debug Toolbar (только в DEBUG режиме)
|
# Django Debug Toolbar
|
||||||
if DEBUG:
|
if DEBUG_TOOLBAR_ENABLED:
|
||||||
INSTALLED_APPS += ['debug_toolbar']
|
INSTALLED_APPS += ['debug_toolbar']
|
||||||
|
|
||||||
# Модели тенанта и домена
|
# Модели тенанта и домена
|
||||||
@@ -110,22 +113,21 @@ SHOW_PUBLIC_IF_NO_TENANT_FOUND = True
|
|||||||
# ============================================
|
# ============================================
|
||||||
|
|
||||||
MIDDLEWARE = [
|
MIDDLEWARE = [
|
||||||
'whitenoise.middleware.WhiteNoiseMiddleware', # Static files first (no DB access needed)
|
'django_tenants.middleware.main.TenantMainMiddleware', # 1. Обязательно первым!
|
||||||
'django_tenants.middleware.main.TenantMainMiddleware', # ОБЯЗАТЕЛЬНО ПЕРВЫМ!
|
'django.middleware.security.SecurityMiddleware', # 2. Безопасность (HTTPS и заголовки)
|
||||||
'myproject.admin_access_middleware.TenantAdminAccessMiddleware', # SECURITY: Ограничение доступа к админке
|
'whitenoise.middleware.WhiteNoiseMiddleware', # 3. Статика (после безопасности)
|
||||||
'django.middleware.security.SecurityMiddleware',
|
|
||||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||||
'django.middleware.common.CommonMiddleware',
|
'django.middleware.common.CommonMiddleware',
|
||||||
'django.middleware.csrf.CsrfViewMiddleware',
|
'django.middleware.csrf.CsrfViewMiddleware',
|
||||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
'django.contrib.auth.middleware.AuthenticationMiddleware', # 4. Определение пользователя
|
||||||
|
'myproject.admin_access_middleware.TenantAdminAccessMiddleware', # 5. ТЕПЕРЬ проверка работает (после auth)
|
||||||
'django.contrib.messages.middleware.MessageMiddleware',
|
'django.contrib.messages.middleware.MessageMiddleware',
|
||||||
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||||
'simple_history.middleware.HistoryRequestMiddleware', # История изменений
|
'simple_history.middleware.HistoryRequestMiddleware',
|
||||||
]
|
]
|
||||||
|
|
||||||
# Django Debug Toolbar Middleware (только в DEBUG режиме)
|
# Django Debug Toolbar Middleware
|
||||||
# ВАЖНО: добавляем ПОСЛЕ TenantMainMiddleware, чтобы toolbar видел корректный tenant
|
if DEBUG_TOOLBAR_ENABLED:
|
||||||
if DEBUG:
|
|
||||||
MIDDLEWARE.append('debug_toolbar.middleware.DebugToolbarMiddleware')
|
MIDDLEWARE.append('debug_toolbar.middleware.DebugToolbarMiddleware')
|
||||||
|
|
||||||
|
|
||||||
@@ -433,23 +435,36 @@ USE_HTTPS = env.bool('USE_HTTPS', default=False)
|
|||||||
# DJANGO DEBUG TOOLBAR SETTINGS
|
# DJANGO DEBUG TOOLBAR SETTINGS
|
||||||
# ============================================
|
# ============================================
|
||||||
|
|
||||||
if DEBUG:
|
# Улучшенный блок INTERNAL_IPS (для Docker и локальной разработки)
|
||||||
# IP адреса, с которых разрешен доступ к Debug Toolbar
|
if DEBUG_TOOLBAR_ENABLED:
|
||||||
INTERNAL_IPS = [
|
import socket
|
||||||
'127.0.0.1',
|
INTERNAL_IPS = ['127.0.0.1', '10.0.2.2', 'localhost']
|
||||||
'localhost',
|
|
||||||
]
|
|
||||||
|
|
||||||
# Если запускаете в Docker, добавьте IP хоста
|
try:
|
||||||
# Например: INTERNAL_IPS += ['172.17.0.1', '192.168.65.1'] # Docker Desktop
|
# Получаем все IP хоста (контейнера)
|
||||||
|
hostname, _, ips = socket.gethostbyname_ex(socket.gethostname())
|
||||||
|
for ip_str in ips:
|
||||||
|
try:
|
||||||
|
# Для IPv4: заменяем последний октет на 1 (шлюз Docker)
|
||||||
|
if '.' in ip_str:
|
||||||
|
parts = ip_str.split('.')
|
||||||
|
if len(parts) == 4:
|
||||||
|
gateway_ip = '.'.join(parts[:3] + ['1'])
|
||||||
|
INTERNAL_IPS.append(gateway_ip)
|
||||||
|
|
||||||
|
# Возможные шлюзы и алиасы
|
||||||
|
INTERNAL_IPS.extend([
|
||||||
|
'.'.join(parts[:3] + ['254']),
|
||||||
|
'host.docker.internal',
|
||||||
|
])
|
||||||
|
except (ValueError, AttributeError):
|
||||||
|
continue
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Debug Info: Could not determine Docker gateway IPs: {e}")
|
||||||
|
|
||||||
# Конфигурация Debug Toolbar
|
# Конфигурация Debug Toolbar
|
||||||
DEBUG_TOOLBAR_CONFIG = {
|
DEBUG_TOOLBAR_CONFIG = {
|
||||||
# Показывать toolbar всегда при DEBUG=True и INTERNAL_IPS
|
'SHOW_TOOLBAR_CALLBACK': lambda request: DEBUG_TOOLBAR_ENABLED,
|
||||||
'SHOW_TOOLBAR_CALLBACK': lambda request: DEBUG,
|
|
||||||
# Или можно фильтровать по tenant (например, только для определенных поддоменов):
|
|
||||||
# 'SHOW_TOOLBAR_CALLBACK': lambda request: DEBUG and getattr(request, 'tenant', None) and request.tenant.schema_name != 'public',
|
|
||||||
# Отключить для тестов
|
|
||||||
'IS_RUNNING_TESTS': False,
|
'IS_RUNNING_TESTS': False,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user