Исправлена критическая уязвимость безопасности, которая потенциально позволяла владельцам тенантов получить доступ к админ-панели 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>
95 lines
4.1 KiB
Python
95 lines
4.1 KiB
Python
# -*- coding: utf-8 -*-
|
||
"""
|
||
Миграция данных для исправления флагов is_staff/is_superuser у существующих пользователей.
|
||
|
||
SECURITY FIX: Убираем флаги is_staff и is_superuser у владельцев тенантов и обычных пользователей,
|
||
которые могли быть созданы до внедрения явных проверок безопасности.
|
||
|
||
Эта миграция должна быть запущена:
|
||
1. На public схеме: python manage.py migrate accounts
|
||
2. На всех tenant схемах: python manage.py migrate_schemas
|
||
"""
|
||
from django.db import migrations
|
||
|
||
|
||
def fix_owner_staff_flags(apps, schema_editor):
|
||
"""
|
||
Исправляет флаги is_staff/is_superuser у существующих владельцев тенантов и обычных пользователей.
|
||
"""
|
||
User = apps.get_model('accounts', 'CustomUser')
|
||
|
||
# Пытаемся получить модели системы ролей (могут не существовать на момент миграции)
|
||
try:
|
||
UserRole = apps.get_model('user_roles', 'UserRole')
|
||
Role = apps.get_model('user_roles', 'Role')
|
||
|
||
# Находим роль owner
|
||
try:
|
||
owner_role = Role.objects.get(code='owner')
|
||
|
||
# Получаем всех пользователей с ролью owner
|
||
owner_user_ids = UserRole.objects.filter(
|
||
role=owner_role,
|
||
is_active=True
|
||
).values_list('user_id', flat=True)
|
||
|
||
# Убираем is_staff и is_superuser у всех владельцев
|
||
updated_staff = User.objects.filter(
|
||
id__in=owner_user_ids,
|
||
is_staff=True
|
||
).update(is_staff=False)
|
||
|
||
updated_super = User.objects.filter(
|
||
id__in=owner_user_ids,
|
||
is_superuser=True
|
||
).update(is_superuser=False)
|
||
|
||
if updated_staff > 0 or updated_super > 0:
|
||
print(f"[SECURITY FIX] Исправлено владельцев: is_staff={updated_staff}, is_superuser={updated_super}")
|
||
|
||
except Role.DoesNotExist:
|
||
print("[SECURITY FIX] Роль 'owner' не найдена, пропускаем исправление владельцев")
|
||
|
||
except LookupError:
|
||
# Модели user_roles еще не существуют - это нормально для новых инсталляций
|
||
print("[SECURITY FIX] Модели user_roles не найдены (это нормально для новых инсталляций)")
|
||
|
||
# Убираем is_staff у всех НЕ-суперпользователей (дополнительная безопасность)
|
||
# Только суперпользователи должны иметь is_staff=True
|
||
updated = User.objects.filter(
|
||
is_staff=True,
|
||
is_superuser=False
|
||
).update(is_staff=False)
|
||
|
||
if updated > 0:
|
||
print(f"[SECURITY FIX] Убран is_staff у {updated} НЕ-суперпользователей")
|
||
|
||
# Итоговая статистика
|
||
total_staff = User.objects.filter(is_staff=True).count()
|
||
total_super = User.objects.filter(is_superuser=True).count()
|
||
print(f"[SECURITY FIX] Текущее состояние: is_staff={total_staff}, is_superuser={total_super}")
|
||
|
||
|
||
def reverse_fix(apps, schema_editor):
|
||
"""
|
||
Откат не требуется - мы только исправляем безопасность, не меняем структуру данных.
|
||
"""
|
||
pass
|
||
|
||
|
||
class Migration(migrations.Migration):
|
||
"""
|
||
Миграция данных для исправления флагов безопасности.
|
||
|
||
ВАЖНО: Эту миграцию нужно запустить на всех тенантах командой:
|
||
python manage.py migrate_schemas
|
||
"""
|
||
|
||
dependencies = [
|
||
('accounts', '0001_initial'),
|
||
]
|
||
|
||
operations = [
|
||
migrations.RunPython(fix_owner_staff_flags, reverse_fix),
|
||
]
|