SSRF: недооценённая уязвимость на границе сети
Функция импорта по URL, предпросмотр ссылки или вебхук могут превратить сервер в прокси к внутренним сервисам. Разбираем, где возникает SSRF, почему проверки адреса недостаточно и какие меры снижают риск.

Функция «загрузить изображение по ссылке» может открыть внешнему пользователю доступ к тому, что сервер видит внутри своей сети. Так работает SSRF: приложение отправляет запрос по адресу, который контролирует пользователь, а ответ иногда возвращает ему или использует в дальнейшей обработке. Цена ошибки — от утечки внутренних данных до доступа к облачным метаданным и сервисам, не рассчитанным на публичный трафик.
Почему серверу доверяют больше, чем браузеру
Браузер посетителя обычно ограничен его устройством и сетевыми настройками. Сервер приложения может иметь доступ к базам данных, внутренним API, панелям управления, очередям задач и адресам облачной инфраструктуры. Если приложение принимает пользовательский URL и само его запрашивает, оно становится посредником между внешним клиентом и этой внутренней сетью.
Уязвимость появляется не только в очевидном поле «URL для скачивания». Источником адреса бывают импорт документов, проверка доступности сайта, генерация превью, обработчик вебхуков, конвертер файлов или функция получения аватара. Запрос может выполнять не основной веб-сервис, а фоновый обработчик — и это не делает его безопасным.
SSRF1 расшифровывается как Server-Side Request Forgery — подделка серверного запроса. Проблема не в самом HTTP-клиенте, а в том, что недоверенный ввод влияет на то, куда сервер обращается и что делает с ответом.
Как из одной ссылки получается инцидент
Типичный сценарий начинается с полезной функции: пользователь указывает адрес, приложение загружает ресурс. Если серверу разрешено обращаться к произвольным адресам, атакующий может попытаться направить запрос не к публичному сайту, а к ресурсу, доступному только из сети приложения. Там могут находиться служебные интерфейсы или данные, которые никогда не предназначались для пользователя.
Даже если тело ответа не показывают, SSRF не обязательно безвредна. Сам факт обращения может запустить действие на внутреннем сервисе; результат может попасть в журнал, очередь или сохранённый файл. А если ответ возвращается пользователю, риск утечки становится прямым. Поэтому проверять нужно всю цепочку: кто задаёт адрес, кто выполняет запрос, куда сохраняется ответ и кто может его прочитать.
Если серверу не нужна возможность ходить по произвольным адресам, не пытайтесь сделать такую возможность «достаточно безопасной». Уберите её или ограничьте разрешёнными направлениями.
Почему одной проверки URL недостаточно
Проверка строки до запроса — полезный слой, но не гарантия. Адреса можно записывать в разных формах, а доменное имя разрешается в IP-адрес уже во время сетевого обращения. Между проверкой имени и подключением возможна смена результата DNS. Клиент также может автоматически следовать перенаправлениям на другой адрес, не проходивший исходную проверку.
Ещё один источник риска — разные интерпретации URL парсером приложения, HTTP-библиотекой и сетевым окружением. Поэтому правило «разрешаем адрес, если он начинается с нужного домена» ненадёжно: совпадение текста не означает, что фактическое соединение пойдёт к ожидаемому узлу.
Отдельно проверьте, что происходит после получения ответа. Ограничьте размер загружаемого ресурса, время ожидания и типы данных, которые приложение принимает дальше. Иначе даже запрос к разрешённому узлу может использоваться для перегрузки обработчика или передачи неожиданного содержимого в парсер.
Защита: несколько рубежей вместо одной регулярки
Надёжная защита начинается с архитектурного решения. Если задаче достаточно выбрать файл из заранее заданного каталога или отправить запрос только к партнёрскому API, не принимайте произвольный URL. Чем меньше свободы у входных данных, тем меньше вариантов обхода.
- Задайте список разрешённых хостов. Сравнивайте разобранное имя хоста целиком, а не ищите подстроку в исходном URL. Если допустимы поддомены, задайте правило границы домена явно.
- Ограничьте сетевой выход. На уровне сети запретите приложению соединения с внутренними диапазонами и служебными сегментами, оставив только необходимые направления. Это сдерживает последствия ошибки в проверке.
- Проверяйте конечное назначение. Учитывайте результат DNS-разрешения и адрес фактического соединения; не полагайтесь только на имя, проверенное раньше.
- Контролируйте перенаправления. Отключите автоматическое следование, если оно не нужно, либо проверяйте каждый новый адрес и его конечное назначение.
- Добавьте лимиты и аудит. Ограничьте время, размер ответа и число перенаправлений. Записывайте домен назначения, результат проверки и причину отказа, но не сохраняйте секреты или полные тела ответов без необходимости.
Список разрешённых хостов удобен, когда интеграций немного и их адреса стабильны. Сетевой запрет важен в любом случае: он действует независимо от того, насколько аккуратно написана проверка в приложении. Контроль перенаправлений и DNS дополняет эти меры, но не заменяет их.
| Подход | Что даёт | Цена и ограничение |
|---|---|---|
| Отказ от пользовательских URL | Убирает сам канал произвольных запросов | Может потребовать изменить продуктовый сценарий |
| Список разрешённых хостов | Ограничивает адреса на уровне приложения | Нужно обслуживать список и проверять реальное назначение |
| Сетевые правила исходящих соединений | Сдерживают ущерб при ошибке в коде | Требуют настройки инфраструктуры и учёта нужных интеграций |
| Контроль DNS и перенаправлений | Закрывает обходы через смену адреса и цепочку переходов | Зависит от поведения конкретного HTTP-клиента и схемы соединения |
Что проверять при ревью и после релиза
Ищите не слово «URL», а поток данных: пользовательский ввод попадает в сетевой запрос напрямую или через очередь, шаблон, конфигурацию интеграции. Затем проследите, применяются ли ограничения к каждому переходу и проверяется ли адрес, к которому установлено соединение. Наличие валидатора в одном месте не доказывает, что им пользуются все обработчики.
В тестовой среде проверьте ожидаемые отказы для адресов вне разрешённого списка, перенаправлений на запрещённые назначения и недоступных DNS-ответов. Не направляйте тесты на чужие внутренние системы. В логах и метриках полезно видеть число блокировок, ошибки разрешения имён, тайм-ауты и объём скачанных данных. Рост отказов может означать как попытки злоупотребления, так и сломавшуюся интеграцию.
Где защита ломается
Сложнее всего не забыть про второй путь к сети: фоновые задачи, конвертеры, генераторы превью и отдельные микросервисы часто имеют другие настройки. Проверка, встроенная только в публичный API, не поможет, если очередь принимает тот же URL без ограничений.
Не считайте блокировку частных адресов универсальным решением. Внутренняя сеть и служебные адреса зависят от инфраструктуры, а разрешённый публичный домен может вести себя не так, как ожидалось, или перенаправлять запрос. Инвентаризируйте реальные исходящие соединения и сверяйте сетевые правила с архитектурой.
Замеры производительности здесь нельзя заменить универсальными цифрами: нагрузка зависит от HTTP-клиента, DNS, тайм-аутов, размера файлов и числа параллельных задач. Сравните задержку и пропускную способность функции до и после ограничений на вашем тестовом стенде; отдельно измерьте поведение при медленном ответе и большом разрешённом файле.
Что делать дальше
Начните с инвентаризации всех функций, которые получают адрес извне и выполняют исходящие запросы. Для каждой зафиксируйте разрешённые назначения, сетевые права процесса, обработку перенаправлений и место хранения ответа. Затем закройте произвольный сетевой выход там, где он не нужен, и добавьте проверки на границе приложения и инфраструктуры.
После этого наблюдайте за отказами и тайм-аутами в проде: они покажут, не заблокировали ли вы нужную интеграцию и не пытается ли какой-то обработчик ходить за пределы ожидаемого списка. Внутреннюю политику исходящих соединений пересматривайте вместе с изменениями интеграций, а не только после инцидента.
1 Исходящий запрос — сетевой запрос, который инициирует само приложение, а не браузер пользователя. В контексте SSRF важно, что такой запрос выполняется с сетевыми правами сервера.
Проверка рекламы на риски: Что в макете вызовет вопросы ФАС: превосходные степени, сравнения, обещания результата, маркировка.
Спросить за 40 ₽Источники: OWASP Cheat Sheet Series: Server Side Request Forgery Prevention, CWE-918: Server-Side Request Forgery (SSRF)
Частые вопросы
SSRF опасна, если приложение не показывает пользователю ответ сервера?
Достаточно ли разрешить только нужный домен?
Можно ли просто запретить частные IP-адреса?
Нужно ли проверять фоновые задачи на SSRF?
Как понять, что защита не сломала нужные интеграции?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.