Статья по безопасности Django REST Framework (DRF Cheat Sheet)
Введение
Эта статья даёт рекомендации по безопасности Django REST Framework для разработчиков — базовый набор правил для тех, кто должен защитить ключевые аспекты приложения на DRF.
Что такое представление (view) в Django?
View в Django — это Python-класс или функция, которая после получения HTTP-запроса возвращает ответ. Ответ может быть простым HTTP, HTML-шаблоном или перенаправлением на другую страницу.
Настройки
Конфигурация DRF задаётся в пространстве имён REST_FRAMEWORK, обычно в settings.py. С точки зрения безопасности важны в первую очередь:
DEFAULT_AUTHENTICATION_CLASSES
Список классов аутентификации по умолчанию: по ним определяется пользователь при обращении к request.user и request.auth. Типично это rest_framework.authentication.SessionAuthentication (сессии) и rest_framework.authentication.BasicAuthentication (Basic).
DEFAULT_PERMISSION_CLASSES
Список классов прав по умолчанию: Django проверяет их до доступа к представлению. Значение по умолчанию — rest_framework.permissions.AllowAny, то есть пока вы не смените класс прав по умолчанию, любой может обращаться к любому представлению.
DEFAULT_THROTTLE_CLASSES
Список классов throttling, проверяемых в начале обработки запроса. По умолчанию throttling отключён: список пустой.
DEFAULT_PAGINATION_CLASS
Класс пагинации для queryset по умолчанию. В Django пагинация по умолчанию выключена. Без пагинации при больших объёмах данных возможны проблемы доступности и DoS.
OWASP API Security Top 10 (2019)
OWASP API Security Top 10 — перечень критичных рисков для API от OWASP, чтобы расставить приоритеты и внедрить контроли.
Ниже используется редакция 2019 года. Рационально идти сверху вниз (от A1), чтобы время уходило на самые серьёзные угрозы. После Top 10 имеет смысл оценить другие риски и при необходимости заказать пентест.
API1:2019 Broken Object Level Authorization
При проверке прав на уровне объекта убедитесь, что пользователю разрешён доступ к объекту, например через .check_object_permissions(request, obj).
Пример:
def get_object(self):
obj = get_object_or_404(self.get_queryset(), pk=self.kwargs["pk"])
self.check_object_permissions(self.request, obj)
return obj
Не переопределяйте get_object() без проверки, что запросу положен доступ к этому объекту.
API2:2019 Broken User Authentication
Чтобы снизить риск слабой аутентификации, задайте в DEFAULT_AUTHENTICATION_CLASSES подходящие для проекта классы и включайте аутентификацию на всех непубличных эндпоинтах. Не переопределяйте authentication_classes на class-based view (атрибут) или function-based view (декоратор), если не уверены в последствиях.
API3:2019 Excessive Data Exposure
В ответах отдавайте минимум необходимых данных. Пересмотрите сериализатор и поля. Если наследуетесь от ModelSerializer, не используйте в Meta свойство exclude (подход «чёрного списка»): лучше явно перечислять разрешённые поля.
API4:2019 Lack of Resources & Rate Limiting
Настройте DEFAULT_THROTTLE_CLASSES и не отключайте throttling на отдельных представлениях через throttle_classes, если нет веской причины.
Дополнительно: по возможности ограничивайте частоту запросов на WAF или аналоге; DRF — последний, а не единственный рубеж rate limiting.
API5:2019 Broken Function Level Authorization
Смените значение по умолчанию DEFAULT_PERMISSION_CLASSES с 'rest_framework.permissions.AllowAny' на классы, соответствующие политике проекта.
rest_framework.permissions.AllowAny — только для явно публичных API. Не переопределяйте permission_classes без понимания эффекта.
API6:2019 Mass Assignment
Для ModelForm используйте Meta.fields (белый список). Не используйте Meta.exclude и не задавайте ModelForms.Meta.fields = "__all__".
API7:2019 Security Misconfiguration
Нужен повторяемый процесс укрепления и быстрого развёртывания заблокированной среды и автоматическая оценка эффективности настроек во всех окружениях.
Не используйте пароли по умолчанию. В Django выставьте DEBUG и DEBUG_PROPAGATE_EXCEPTIONS в False. Разрешайте только нужные HTTP-глаголы; остальные отключите. SECRET_KEY — случайное значение; секреты никогда не хардкодьте.
Проверяйте, фильтруйте и нормализуйте все данные от клиента и из интеграций.
API8:2019 Injection
SQLi
Используйте параметризованные запросы. Осторожно с raw(), extra() и произвольным SQL через cursor.execute(). Не подставляйте пользовательский ввод в эти API.
RCE
Для YAML указывайте Loader=yaml.SafeLoader. Не загружайте контролируемый пользователем YAML через yaml.load() без безопасного загрузчика.
Также не передавайте пользовательский ввод в eval(), exec() (и в Python 2 — execfile()) и не загружайте pickle-файлы из недоверенных источников, включая pandas.read_pickle().
API9:2019 Improper Assets Management
Ведите инвентаризацию хостов API: версия API, окружение (prod, staging, test, dev), кто должен иметь сетевой доступ (публично, только внутри, партнёры). Документируйте аутентификацию, ошибки, редиректы, rate limiting, CORS и эндпоинты с параметрами, телами запросов и ответов.
API10:2019 Insufficient Logging & Monitoring
Для журналирования и мониторинга:
- Логируйте неуспешную аутентификацию, отказ в доступе и ошибки валидации с достаточным контекстом пользователя.
- Формат логов должен подходить для SIEM/log management; деталей должно хватать, чтобы выявить злоумышленника.
- Относитесь к логам как к чувствительным данным; обеспечьте целостность в покое и при передаче.
- Настройте мониторинг инфраструктуры, сети и работы API.
- Агрегируйте логи со всего стека API в SIEM.
- Настройте дашборды и оповещения для раннего обнаружения подозрительной активности.
- Обеспечьте своевременную реакцию на инциденты.
Не делайте так:
- Не пишите в лог только общие сообщения вроде
Log.Error("Error was thrown")— добавляйте stack trace, текст ошибки и идентификатор пользователя. - Не логируйте пароли, API-токены и персональные данные.
Другие риски
Ниже — риски вне перечня OWASP API Security Top 10.
Ошибки бизнес-логики
Ошибки бизнес-логики часто не ловятся автоматическими сканерами. Снижайте риск через моделирование угроз, security design review, code review, парное программирование и модульные тесты.
Управление секретами
Секреты не должны быть в коде. Предпочтительно использовать менеджер секретов. Подробнее — Secrets Management Cheat Sheet.
Обновление Django, DRF и зависимостей
У приложений есть зависимости; в них бывают уязвимости. Полезно регулярно аудировать зависимости и иметь процесс обновления. Пример триггеров:
- раз в месяц/квартал — плановое обновление зависимостей;
- раз в неделю — разбор критичных уязвимостей и при необходимости срочное обновление;
- в исключительных случаях — экстренные патчи.
Команда безопасности Django публикует как раскрываются проблемы безопасности.
Оценивайте «здоровье» библиотеки: частота обновлений, известные CVE, активность сообщества. Помогают инструменты вроде Snyk Advisor.
SAST-инструменты
Примеры открытых статических анализаторов для Python:
Bandit — Bandit: ищет типичные проблемы безопасности; строит AST и прогоняет плагины; в итоге отчёт. Изначально в OpenStack Security Project, затем в PyCQA.
Semgrep — Semgrep: быстрый SAST по правилам (безопасность, стиль кода и др.). Для Django есть набор правил.
PyCharm Security — pycharm-security: плагин для PyCharm / JetBrains IDE с Python; ищет типичные уязвимости и предлагает исправления; можно запускать из Docker. Часть проверок специфична для Django.
Связанные материалы
© Перевод на русский язык. Оригинальные материалы: OWASP Cheat Sheet Series.
Этот проект использует материалы OWASP, распространяемые по лицензии CC BY-SA 4.0.