Уязвимость в продакшене стоит дороже любого бага. На собесе бэкендера спрашивают классику веб-безопасности и её конкретные проявления в Django и FastAPI. Важно не перечислить аббревиатуры, а показать, как вы пишете код, чтобы они не случались.
SQL-инъекция
# уязвимо: пользовательский ввод становится частью SQL
cursor.execute(f"SELECT * FROM users WHERE email = '{email}'")
# безопасно: параметры передаются отдельно от текста запроса
cursor.execute('SELECT * FROM users WHERE email = %s', [email])
User.objects.raw('SELECT * FROM users WHERE email = %s', [email])
session.execute(text('SELECT * FROM users WHERE email = :email'), {'email': email})
ORM экранирует значения сам, опасны raw(), extra(), RawSQL, text() и f-строки внутри них. Имена колонок и направление сортировки параметрами не передаются, поэтому их берут из белого списка.
XSS
Межсайтовый скриптинг: чужой скрипт выполняется в браузере пользователя. Шаблоны Django и Jinja2 (с включённым autoescape) экранируют вывод автоматически. Опасны mark_safe, фильтр |safe, {% autoescape off %}, вставка пользовательского HTML и формирование HTML в Python строками. Если нужен пользовательский HTML (редактор статей), его очищают библиотекой-санитайзером по белому списку тегов (например, nh3). Дополнительная защита: заголовок Content-Security-Policy и cookie с HttpOnly.
CSRF
Злой сайт заставляет браузер пользователя отправить запрос на ваш сайт с его cookie. Защита в Django: CsrfViewMiddleware и токен в формах, плюс SameSite у cookie. API с токеном в заголовке Authorization (не в cookie) к CSRF не уязвимы, а вот API на сессионных cookie уязвимы, и @csrf_exempt там опасен.
SSRF
Сервер по запросу пользователя ходит по URL (превью ссылки, загрузка аватара по ссылке, вебхуки). Атакующий подсовывает http://169.254.169.254/ (метаданные облака) или http://localhost:6379/ и читает внутренние ресурсы. Защита: белый список доменов, разрешение DNS и запрет приватных и служебных адресов (с проверкой и после редиректов), отдельный исходящий прокси, таймауты и лимит размера ответа.
Загрузка файлов и пути
- Не доверять имени файла от пользователя: генерировать своё имя, проверять тип по содержимому, ограничивать размер.
- Отдавать пользовательские файлы с другого домена или с
Content-Disposition: attachment, иначе загруженный HTML или SVG станет XSS. - Path traversal:
open(os.path.join(BASE, filename))сfilename = '../../etc/passwd'. Нужно нормализовать путь и проверять, что он внутри разрешённого каталога.
Опасные функции Python
pickle.loads,yaml.loadбезSafeLoader,eval,execна пользовательских данных: выполнение произвольного кода.subprocessсshell=Trueи строкой из ввода: инъекция команд.randomдля токенов вместоsecrets.
Открытые редиректы
redirect(request.GET['next']) позволяет отправить пользователя на фишинговый сайт с доверенного домена. Разрешают только относительные пути своего сайта (в Django url_has_allowed_host_and_scheme).
Настройки и секреты
DEBUG = False,ALLOWED_HOSTS, HTTPS-редирект и HSTS,SESSION_COOKIE_SECURE,CSRF_COOKIE_SECURE.- Секреты в переменных окружения или менеджере секретов, не в git. Утёкший секрет считать скомпрометированным и ротировать.
- Зависимости: lock-файл, проверка уязвимостей (pip-audit, Dependabot), своевременные обновления.
- Лимиты: размер тела запроса, частота запросов, таймауты.
Частые ошибки
- f-строки в SQL и в
text(). |safeна пользовательском вводе.csrf_exemptна эндпоинтах с сессионной авторизацией.- Загрузка по URL без защиты от SSRF.
pickleдля данных из внешних источников.- Подробные ошибки и трейсбэки, отдаваемые клиенту.
Что спросят на собесе
- Что такое SQL-инъекция и почему ORM от неё защищает, а где нет.
- Как Django защищает от XSS и CSRF.
- Что такое SSRF и как защитить загрузку по ссылке.
- Почему опасны
pickle,eval,shell=True. - Что проверить в настройках перед выкладкой.