Этот модуль про уязвимости, где приложение работает с адресами и путями от пользователя: ходит по URL, открывает файлы, принимает загрузки, перенаправляет.
SSRF
Server-Side Request Forgery: сервер делает запрос по адресу, который задал атакующий. Типичные функции: превью ссылок, загрузка аватара по URL, вебхуки, импорт по ссылке, PDF-генератор, который грузит картинки.
Что достаёт атакующий:
- Внутренние сервисы: админки, базы, Redis, Elasticsearch без пароля, доступные только из внутренней сети.
- Метаданные облака:
http://169.254.169.254/отдаёт временные ключи IAM-роли сервера. Это классический путь от SSRF к захвату облачного аккаунта. В AWS защищает IMDSv2: нужен токен, полученный PUT-запросом, а простой GET через SSRF его не получит. - Сканирование внутренней сети по времени ответа.
Почему наивные проверки не работают:
- Чёрный список строк (
localhost,127.0.0.1) обходится:127.1,2130706433,0x7f000001,[::1],[::ffff:127.0.0.1], домен, который резолвится в127.0.0.1. - Редиректы: внешний URL отвечает 302 на внутренний адрес.
- DNS rebinding: при проверке имя резолвится во внешний IP, а при запросе уже во внутренний.
Защита:
- Allowlist доменов, если сценарий позволяет (вебхуки только на зарегистрированные адреса, картинки только с вашего CDN).
- Разрешить только схемы
httpиhttps, нужные порты. - Резолвить имя самому, проверить IP (не приватный, не loopback, не link-local, не зарезервированный) и подключаться к проверенному IP, а не к имени повторно.
- Не следовать редиректам автоматически или проверять каждый шаг.
- Сетевая изоляция: исходящие запросы через отдельный egress-прокси, у которого нет доступа во внутреннюю сеть. Это самая надёжная мера.
- IMDSv2 и минимальные права у роли сервера.
- Не отдавать пользователю сырой ответ и подробные ошибки.
Path traversal
open("/srv/files/" + request.args["name"]) # name = "../../etc/passwd"
Защита:
- По возможности не использовать имя от пользователя: хранить файл под сгенерированным id, а исходное имя держать в базе.
- Если путь нужен: нормализовать (
realpath), затем проверить, что результат внутри базовой папки (commonpath), а не просто «начинается со строки»:/srv/files2начинается с/srv/files. - Отклонять абсолютные пути, нулевой байт, обратные слэши.
- Запускать приложение с минимальными правами на файловую систему.
Загрузка файлов
- Проверять тип по содержимому, а не по расширению и
Content-Typeот клиента. - Генерировать имя на сервере, хранить вне веб-корня или в объектном хранилище.
- Ограничивать размер и число файлов, распаковку архивов (zip bomb, zip slip: путь
../внутри архива). - Отдавать с
Content-Disposition: attachmentиX-Content-Type-Options: nosniff, лучше с отдельного домена: иначе загруженный HTML или SVG станет хранимым XSS. - Изображения перекодировать, чтобы убрать метаданные и вредное содержимое.
XXE
XML External Entity: парсер XML разрешает внешние сущности, и документ вида <!ENTITY x SYSTEM "file:///etc/passwd"> читает файлы или делает SSRF. Защита: отключить DTD и внешние сущности в парсере (в Python использовать defusedxml), по возможности JSON вместо XML. Опасны и форматы на основе XML: DOCX, SVG, SAML.
Открытый редирект
https://site.ru/login?next=https://evil.ru
После входа сайт перенаправляет на адрес атакующего. Пользователь видел настоящий домен, поэтому фишинг выглядит убедительно. В OAuth открытый редирект помогает украсть код авторизации.
Защита: разрешать только локальные пути (/dashboard) или идентификаторы страниц из списка. Строка должна начинаться с одного /: //evil.ru и /\evil.ru браузер воспринимает как адрес другого хоста.
Частые ошибки
- Проверить URL строкой, а запрос сделать по имени, которое резолвится заново.
- Следовать редиректам при скачивании по URL.
startswith(base)вместо проверки вхождения в папку.- Доверять расширению файла.
Что спросят на собесе
- Что такое SSRF и почему он опасен в облаке.
- Как правильно защитить функцию «загрузить картинку по URL».
- Как обходят чёрные списки адресов.
- Как безопасно отдавать файлы по имени.
- Чем опасен открытый редирект.