SECURITY: Ограничен доступ владельцев тенантов к админке Django

Исправлена критическая уязвимость безопасности, которая потенциально позволяла
владельцам тенантов получить доступ к админ-панели Django.

Изменения:
- Добавлены явные setdefault для is_staff=False и is_superuser=False в CustomUserManager.create_user()
- Добавлены явные флаги безопасности при создании владельца тенанта
- Добавлены явные флаги безопасности при создании пользователей через систему ролей
- Создан TenantAdminAccessMiddleware для защиты /admin/ на уровне middleware
- Создана миграция данных для исправления флагов у существующих пользователей

Реализована трёхуровневая защита (Defense-in-Depth):
1. Уровень модели: явные дефолты в create_user()
2. Уровень views: явные флаги при создании
3. Уровень middleware: runtime блокировка доступа

Файлы:
- accounts/models.py: явные флаги в create_user()
- tenants/admin.py: явные флаги при создании владельца
- user_roles/views.py: явные флаги при создании через роли
- myproject/admin_access_middleware.py: новый middleware
- myproject/settings.py: регистрация middleware
- accounts/migrations/0002_fix_owner_staff_flags.py: миграция данных

ВАЖНО: После применения этого коммита необходимо выполнить:
1. python manage.py migrate accounts
2. python manage.py migrate_schemas

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-12-02 10:57:39 +03:00
parent 0c64aac570
commit 0d3f07ad25
6 changed files with 151 additions and 2 deletions

View File

@@ -0,0 +1,44 @@
# -*- coding: utf-8 -*-
"""
Middleware для ограничения доступа к админке Django на поддоменах тенантов.
SECURITY: Этот middleware обеспечивает дополнительный слой защиты,
блокируя доступ владельцев тенантов к /admin/ даже если у них
случайно установлен is_staff=True.
Правила доступа:
- На tenant поддоменах (shop1.localhost): только is_superuser=True может входить в /admin/
- На public схеме (localhost): обычные правила Django (is_staff=True достаточно)
- Суперпользователи имеют доступ везде
"""
from django.http import HttpResponseForbidden
class TenantAdminAccessMiddleware:
"""
Дополнительный слой безопасности: блокирует доступ владельцев тенантов к /admin/
даже если у них случайно установлен is_staff=True.
"""
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
# Проверяем, это admin URL?
if request.path.startswith('/admin/'):
from django.db import connection
# Если мы в tenant схеме (не public)
if hasattr(connection, 'tenant') and connection.tenant:
# Проверяем: это не public схема?
if connection.tenant.schema_name != 'public':
# Если пользователь авторизован, но НЕ суперпользователь - блокируем
if request.user.is_authenticated and not request.user.is_superuser:
return HttpResponseForbidden(
"Доступ запрещен. Только системные администраторы могут "
"заходить в админ-панель на поддоменах тенантов. "
"Используйте панель управления тенанта."
)
response = self.get_response(request)
return response

View File

@@ -95,6 +95,7 @@ SHOW_PUBLIC_IF_NO_TENANT_FOUND = True
MIDDLEWARE = [
'django_tenants.middleware.main.TenantMainMiddleware', # ОБЯЗАТЕЛЬНО ПЕРВЫМ!
'myproject.admin_access_middleware.TenantAdminAccessMiddleware', # SECURITY: Ограничение доступа к админке
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',