Skip to content

Безопасность и аудит

Аутентификация

Token Authentication

Система использует DRF TokenAuthentication — простой и надёжный механизм для REST API:

python
# Получить токен
POST /api/v2/api-token-auth/
{"username": "user@example.com", "password": "password"}

# Ответ
{"token": "9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b"}

# Использование в запросах
Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b

Токены хранятся в таблице authtoken_token. Каждый пользователь имеет один токен.

Инвалидация токена

При выходе из системы токен удаляется:

python
DELETE /api/v2/logout/
# Удаляет Token для текущего пользователя

Авторизация (Права доступа)

Глобальная политика

python
REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.IsAuthenticated',
    ],
}

Все endpoints требуют аутентификации. Исключения задаются явно.

Кастомные права

Frontend проверяет права через PermissionService (libs/core/services/permission.service.ts):

  • Директива HasPermissionDirective скрывает элементы UI
  • Guard auth.guard.ts защищает маршруты

Роли (Guards на фронтенде)

GuardДоступ
AuthGuardЛюбой авторизованный пользователь
AccountantGuardБухгалтер (ограниченный доступ)
WarehouseWorkerGuardСкладской работник
DriverWorkerGuardВодитель
SuperUserGuardАдминистратор системы

Система аудита

django-simple-history

Модуль simple_history автоматически сохраняет историю изменений моделей:

python
from simple_history.models import HistoricalRecords

class Documents(MPTTModel):
    # ...
    history = HistoricalRecords()

Для каждой модели с историей создаётся таблица historical_*. Хранит:

  • Дата и время изменения
  • Кто изменил (history_user)
  • Тип операции (создание / обновление / удаление)
  • Снимок объекта в момент изменения

system.auditlog

Дополнительный аудит-лог (system.auditlog) — кастомный модуль:

python
class LogEntry(Model):
    user = FK(User)
    action = CharField()         # 'create', 'update', 'delete'
    content_type = FK(ContentType)
    object_id = IntegerField()
    object_repr = CharField()    # строковое представление
    changes = JSONField()        # JSON с изменёнными полями
    timestamp = DateTimeField()
    ip_address = GenericIPAddressField()

Просмотр лога: Django Admin → System → Audit Log Entries

CORS

python
# settings.py
CORS_ORIGIN_ALLOW_ALL = True   # в dev-режиме
CORS_ORIGIN_WHITELIST = [
    "http://localhost:4200",
    "https://office.narmak.ru",
]

В production CORS_ORIGIN_ALLOW_ALL = False и используется whitelist.

Хранение файлов (Selectel)

Файлы загружаются в облачное хранилище Selectel Object Storage:

python
SELECTEL_STORAGE = {
    'container_name': 'narmak-files',
    'user': '...',
    'key': '...',
}
DEFAULT_FILE_STORAGE = 'django_selectel.storage.SelectelStorage'

Прямые URL файлов недоступны без токена (приватный контейнер).

Защита API от перебора

  • Rate limiting через Django middleware (настраивается в settings.py)
  • При 5 неудачных попытках входа — временная блокировка IP

Рекомендации по безопасности

АспектСтатусРекомендация
HTTPSТребует настройки nginxИспользовать Let's Encrypt
SECRET_KEYИз settings.iniХранить в env-переменных
DEBUG=FalseВ productionПроверить перед деплоем
CORSWhitelist в prodУбрать ALLOW_ALL
ТокеныНе истекаютРассмотреть JWT с expiry
Паролиbcrypt (Django default)Минимальная длина 8 символов