Django — один из самых популярных Python-фреймворков, известный своим девизом «включено из коробки». Его встроенные механизмы безопасности создают иллюзию неуязвимости, что и становится ловушкой для многих разработчиков.
Опытный пентестер знает: стандартные настройки — это не магический щит. В этом руководстве мы разберем, как проводить тестирование на проникновение веб-приложений на Django, фокусируясь на трех ключевых аспектах: уязвимости ORM, обход CSRF-защиты и атаки на механизм сессий. Этот материал рассчитан на специалистов по безопасности и разработчиков, желающих углубить свои знания.
1. Почему Django — особый случай для пентеста?
Django предоставляет мощные абстракции. Но именно эти абстракции создают уникальные векторы атак, которые не видны в других фреймворках.
- ORM: Позволяет не писать SQL вручную, но может генерировать неэффективные или небезопасные запросы.
- CSRF-токены: Включены по умолчанию, но их реализация может быть скомпрометирована неверной конфигурацией.
- Сессии: По умолчанию хранятся в подписанных cookie, что удобно, но таит риски, если секретный ключ скомпрометирован.
Цель пентеста — найти бреши там, где разработчик слишком положился на «магию» фреймворка.
2. Тестирование ORM на уязвимости к инъекциям
Миф: «Django ORM на 100% защищает от SQL-инъекций». Это почти правда, но есть опасные исключения.
Вектор атаки №1: Небезопасное использование RawSQL и extra()
Пентестер должен искать в коде (белый ящик) или методом fuzzing (черный ящик) использование этих методов.
- Уязвимый код:
- Опасный подход!
query = "SELECT * FROM users WHERE username = %s" % username User.objects.raw(query) - Эксплуатация: Классическая SQL-инъекция через параметр
username. - Безопасная альтернатива:
- Безопасный подход с параметризованными запросами
User.objects.raw('SELECT * FROM users WHERE username = %s', [username])
Вектор атаки №2: Инъекция через аннотации и агрегации
Сложные запросы с использованием annotate() и aggregate() могут включать недоверенные данные.
- Что искать: Динамическое построение запросов с конкатенацией строк для названий полей или таблиц.
- Методика тестирования: Подавать на вход параметры с символами SQL-инъекции и анализировать ответы сервера (ошибки 500, аномальное поведение).
Рекомендация по защите: Всегда использовать встроенные механизмы экранирования Django ORM, избегать конкатенации. Проводить статический анализ кода (SAST) на наличие опасных методов.
3. Обход встроенной CSRF-защиты
CSRF-токены в Django robust по умолчанию. Но пентестер ищет слабые места в их реализации.
Вектор атаки №1: Нестрогая проверка Referer Header
В некоторых конфигурациях (например, при старом настройке CSRF_TRUSTED_ORIGINS) Django может слабо проверять заголовок Referer.
- Методика тестирования:
- Перехватить валидный запрос с токеном (например, форму смены пароля).
- Удалить или подменить заголовок
Referer. - Если запрос выполняется успешно — уязвимость найдена.
Вектор атаки №2: Уязвимости CORS в связке с SPA
Если фронтенд (Vue.js, React) на отдельном домене неправильно сконфигурирован (разрешает запросы с любых доменов), это может позволить атакующему сайту получить валидный CSRF-токен через предварительный запрос (preflight request).
- Что проверять: Настройки CORS на бэкенде (
django-cors-headers). Разрешены ли запросы сOrigin: *?
Вектор атаки №3: Межсайтовое сканирование (XSS)
Если на сайте есть даже незначительная XSS-уязвимость, она может быть использована для чтения валидного CSRF-токена и подмены запроса.
- Комбинированная атака: XSS + CSRF = максимальный impact.
Рекомендация по защите: Убедиться, что CSRF_COOKIE_HTTPONLY = True, CSRF_COOKIE_SAMESITE = 'Lax' (или ‘Strict’), и правильно настроен CSRF_TRUSTED_ORIGINS.
4. Атаки на механизм сессий Django
Django по умолчанию использует подписанные cookie для хранения сессий. Это удобно, но не идеально.
Вектор атаки №1: Компрометация ключа SECRET_KEY
Если злоумышленник получает SECRET_KEY (через утечку в Git, ошибки настроек сервера), он может:
- Подписывать любые данные: Создать валидную сессию для любого пользователя.
- Читать данные сессии, если используется хранение в cookie.
- Методика тестирования: Проверить, не hardcoded ли ключ в публичных репозиториях. Проверить права доступа к файлу
settings.pyна сервере.
Вектор атаки №2: Принудительное использование небезопасного механизма сессий
По умолчанию сессии хранятся в cookie. Но если разработчик в целях производительности переключил хранение в базу данных или кеш (Redis), возможны новые уязвимости:
- Небезопасное хранилище: Redis без пароля.
- Session Fixation: Если идентификатор сессии не перевыпускается после логина.
- Что проверять: Настройку
SESSION_ENGINE. Провести классическое тестирование на Session Fixation.
Рекомендация по защите: Регулярно менять SECRET_KEY, никогда не коммитить его в репозиторий. Использовать django-environ для управления секретами. Для высоконагруженных проектов — использовать базу или кеш для сессий, но обеспечивать их максимальную защиту.
5. Инструменты для автоматического тестирования
Ручной пентест эффективен, но его нужно дополнять автоматизацией.
- Burp Suite Professional:
- Сканер — хорошо находит стандартные уязвимости, но может слепнуть к специфике Django.
- Extensions — ищите кастомные расширения для анализа Django-шаблонов.
- OWASP ZAP: Бесплатная альтернатива, имеет активные и пассивные сканеры.
- Semgrep (SAST): Для статического анализа кода. Имеет готовые правила для поиска уязвимых мест в Django-коде (например,
raw()). - Самописные скрипты на Python: Для фаззинга API и проверки конкретных подозрений.
Чек-лист пентестера Django:
- Проверен код на использование
raw(),extra(). - Протестирована обработка ошибок (не раскрываются ли детали в
DEBUG=True?). - Проверены заголовки
Refererи CORS для обхода CSRF. - Проведен аудит конфигурации:
SECRET_KEY,SESSION_ENGINE,CSRF_TRUSTED_ORIGINS. - Проверены настройки файловых прав и доступа к серверу.
Мой опыт: Типичные ошибки, которые мы находим снова и снова
В своей практике мы провели десятки аудитов проектов на Django. И вот топ-3 ошибки, которые встречаются даже в крупных и зрелых проектах:
- «Магический»
SECRET_KEYв открытом доступе.- Ситуация: Самый частый и критичный промах.
SECRET_KEY, закоммиченный в публичный репозиторий на GitHub или отправленный по почте. Разработчики часто не осознают его ценность. - Последствия: Полная компрометация проекта. Злоумышленник может сгенерировать валидные сессионные куки для любого пользователя, включая администратора.
- Наше решение: Первое, что мы делаем — проверяем историю Git и открытые источники на утечку этого ключа. Рекомендуем использовать
django-environи строгое разграничение доступа к настройкам.
- Ситуация: Самый частый и критичный промах.
- Слепая вера в ORM.
- Ситуация: Разработчик, желая решить сложную задачу, добавляет кастомный SQL-запрос через
RawSQL, но делает это небезопасно, используя конкатенацию строк. - Последствия: Классическая SQL-инъекция в самом неожиданном месте, которое не проверяют стандартные сканеры.
- Наше решение: Мы не просто ищем
raw(), мы анализируем контекст его использования. Мы смотрим, откуда приходят данные в запрос и можно ли их контролировать извне.
- Ситуация: Разработчик, желая решить сложную задачу, добавляет кастомный SQL-запрос через
- Неверная конфигурация CORS для SPA.
- Ситуация: Фронтенд на Vue.js/React вынесен на отдельный поддомен. Backend на Django. Чтобы все работало, разработчик в настройках
django-cors-headersвыставляетCORS_ORIGIN_ALLOW_ALL = Trueи… благополучно забывает. - Последствия: Любой сайт в интернете может сделать запрос к вашему API от имени пользователя (если тот авторизован), что открывает путь для атак на целостность данных.
- Наше решение: Мы всегда проверяем заголовки CORS и
Originв ответах сервера. Рекомендуем явно прописывать разрешенные домены в продакшене.
- Ситуация: Фронтенд на Vue.js/React вынесен на отдельный поддомен. Backend на Django. Чтобы все работало, разработчик в настройках
Вывод из нашего опыта: Основная проблема — не уязвимости самого Django, а миссия его безопасности. Разработчики, прочитав о «встроенной защите», расслабляются и перестают думать о безопасности как о процессе. Задача профессионального пентеста — вернуть это мышление.
Заключение: Иллюзия безопасности стандартных настроек
Django — это мощный и безопасный фреймворк, но он не подменяет собой необходимость думать о безопасности. Как показало это руководство, стандартные настройки — это основа, которую нужно укреплять и адаптировать под конкретный проект. Задача пентестера — мыслить как разработчик, который ищет короткие пути, и находить те самые места, где фреймворковая «магия» дала сбой.
Ключевой вывод: Самые критичные уязвимости в Django-приложениях возникают не из-за слабости фреймворка, а из-за непонимания его внутренних механизмов и неверной конфигурации.
