From b7fffb55bf1a2f02f3d6c2491ab99d71887ba2a4 Mon Sep 17 00:00:00 2001 From: Andrey Smakotin Date: Wed, 7 Jan 2026 23:14:51 +0300 Subject: [PATCH] Security: fix middleware order and CSRF protection --- myproject/myproject/settings.py | 73 ++++++++++++++++++++------------- 1 file changed, 44 insertions(+), 29 deletions(-) diff --git a/myproject/myproject/settings.py b/myproject/myproject/settings.py index 7806706..efd7503 100644 --- a/myproject/myproject/settings.py +++ b/myproject/myproject/settings.py @@ -18,7 +18,7 @@ BASE_DIR = Path(__file__).resolve().parent.parent # Initialize environment variables env = environ.Env( # Set casting and default values - DEBUG=(bool, True), + DEBUG=(bool, False), # Security: default False SECRET_KEY=(str, 'django-insecure-default-key-change-in-production'), ) @@ -36,16 +36,19 @@ if env_file.exists(): SECRET_KEY = env('SECRET_KEY') # 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=['*']) -# CSRF trusted origins для работы за nginx proxy +# CSRF configuration CSRF_TRUSTED_ORIGINS = env.list('CSRF_TRUSTED_ORIGINS', default=[ 'https://mix.smaa.by', 'https://*.mix.smaa.by', ]) +CSRF_USE_SESSIONS = True # Рекомендуется для мультихостовых систем # ============================================ @@ -93,8 +96,8 @@ TENANT_APPS = [ # Объединяем для INSTALLED_APPS INSTALLED_APPS = list(SHARED_APPS) + [app for app in TENANT_APPS if app not in SHARED_APPS] -# Django Debug Toolbar (только в DEBUG режиме) -if DEBUG: +# Django Debug Toolbar +if DEBUG_TOOLBAR_ENABLED: INSTALLED_APPS += ['debug_toolbar'] # Модели тенанта и домена @@ -110,22 +113,21 @@ SHOW_PUBLIC_IF_NO_TENANT_FOUND = True # ============================================ MIDDLEWARE = [ - 'whitenoise.middleware.WhiteNoiseMiddleware', # Static files first (no DB access needed) - 'django_tenants.middleware.main.TenantMainMiddleware', # ОБЯЗАТЕЛЬНО ПЕРВЫМ! - 'myproject.admin_access_middleware.TenantAdminAccessMiddleware', # SECURITY: Ограничение доступа к админке - 'django.middleware.security.SecurityMiddleware', + 'django_tenants.middleware.main.TenantMainMiddleware', # 1. Обязательно первым! + 'django.middleware.security.SecurityMiddleware', # 2. Безопасность (HTTPS и заголовки) + 'whitenoise.middleware.WhiteNoiseMiddleware', # 3. Статика (после безопасности) 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', '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.middleware.clickjacking.XFrameOptionsMiddleware', - 'simple_history.middleware.HistoryRequestMiddleware', # История изменений + 'simple_history.middleware.HistoryRequestMiddleware', ] -# Django Debug Toolbar Middleware (только в DEBUG режиме) -# ВАЖНО: добавляем ПОСЛЕ TenantMainMiddleware, чтобы toolbar видел корректный tenant -if DEBUG: +# Django Debug Toolbar Middleware +if DEBUG_TOOLBAR_ENABLED: MIDDLEWARE.append('debug_toolbar.middleware.DebugToolbarMiddleware') @@ -433,23 +435,36 @@ USE_HTTPS = env.bool('USE_HTTPS', default=False) # DJANGO DEBUG TOOLBAR SETTINGS # ============================================ -if DEBUG: - # IP адреса, с которых разрешен доступ к Debug Toolbar - INTERNAL_IPS = [ - '127.0.0.1', - 'localhost', - ] - - # Если запускаете в Docker, добавьте IP хоста - # Например: INTERNAL_IPS += ['172.17.0.1', '192.168.65.1'] # Docker Desktop +# Улучшенный блок INTERNAL_IPS (для Docker и локальной разработки) +if DEBUG_TOOLBAR_ENABLED: + import socket + INTERNAL_IPS = ['127.0.0.1', '10.0.2.2', 'localhost'] + try: + # Получаем все 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_CONFIG = { - # Показывать toolbar всегда при DEBUG=True и INTERNAL_IPS - 'SHOW_TOOLBAR_CALLBACK': lambda request: DEBUG, - # Или можно фильтровать по tenant (например, только для определенных поддоменов): - # 'SHOW_TOOLBAR_CALLBACK': lambda request: DEBUG and getattr(request, 'tenant', None) and request.tenant.schema_name != 'public', - # Отключить для тестов + 'SHOW_TOOLBAR_CALLBACK': lambda request: DEBUG_TOOLBAR_ENABLED, 'IS_RUNNING_TESTS': False, }