Server-Side Request Forgery (SSRF) - це вразливість вебзастосунків, яка дозволяє зловмиснику змусити сервер виконати HTTP-запит до ресурсу, який сам зловмисник напряму відкрити не може.
На перший погляд це може звучати не дуже небезпечно: ну подумаєш, сервер зробив HTTP-запит. Але проблема в тому, що сервер часто має доступ до внутрішніх ресурсів, яких немає у відкритому інтернеті.
Наприклад, до внутрішніх API, баз даних, адміністративних панелей або cloud metadata-сервісів.
Як працює SSRF
Уявімо простий сервіс, який дозволяє завантажити файл за URL:
https://example.com/download?url=https://tseivo.com/image.jpg
Сервер отримує адресу та сам завантажує файл:
Користувач
│
│ URL
▼
Вебзастосунок
│
│ HTTP request
▼
https://tseivo.com/image.jpg
Це цілком нормальна функція.
Але якщо сервер не перевіряє переданий URL, користувач може замість зовнішнього сайту вказати внутрішню адресу:
https://example.com/download?url=http://127.0.0.1:8080/admin
Тепер запит до 127.0.0.1:8080 виконує сам сервер.
Для атакуючого це може бути особливо цікаво, якщо на цьому порту працює внутрішній сервіс.
Чому сервер може побачити те, чого не бачить зловмисник
Уявімо інфраструктуру:
Internet
│
┌─────▼─────┐
│ Web server │
└─────┬─────┘
│
┌─────────┼─────────┐
▼ ▼ ▼
Internal Database Admin
API panel
З інтернету доступний лише Web Server.
Але сам Web Server може мати доступ до Internal API, бази даних або адміністративної панелі.
SSRF фактично використовує сервер як посередника:
Хакер
│
│ "Зроби запит сюди"
▼
Web Server
│
│ запит від імені сервера
▼
Internal Service
Тобто firewall може чудово блокувати прямий доступ зловмисника до Internal API, але SSRF дозволяє обійти це обмеження через сервер, який уже має необхідний доступ.
SSRF та localhost
Один із найпростіших варіантів атаки - звернення до localhost:
http://127.0.0.1/
http://localhost/
Або до конкретного порту:
http://127.0.0.1:3000/
http://127.0.0.1:8080/
Це може дозволити отримати доступ до сервісів, які навмисно слухають лише локальний інтерфейс.
Наприклад, у production може працювати внутрішня адміністративна панель:
http://127.0.0.1:8080/admin
Ззовні вона недоступна.
Але якщо ваш застосунок має SSRF, він може сам зробити запит до цієї панелі.
SSRF у хмарній інфраструктурі
Особливо серйозною SSRF стає у хмарних середовищах.
У деяких cloud-платформах сервер може звертатися до спеціального metadata service, через який можна отримати інформацію про поточний instance або його credentials.
Наприклад, застосунок може мати доступ до metadata endpoint, а зловмисник ні.
Якщо зловмисник знаходить SSRF, він може спробувати змусити сервер звернутися до цього endpoint.
У найгіршому випадку це може призвести до отримання credentials і подальшого доступу до ресурсів хмарної інфраструктури.
Саме тому SSRF часто розглядають не просто як проблему з HTTP-запитами, а як потенційний шлях до компрометації всієї інфраструктури.
Де найчастіше виникає SSRF
SSRF варто шукати у функціях, де сервер отримує URL від користувача.
Наприклад:
- завантаження зображень за URL;
- імпорт даних із зовнішнього API;
- webhook-и;
- перевірка URL;
- генерація preview вебсторінки;
- PDF або screenshot-сервіси;
- URL unfurling у чатах;
- інтеграції з іншими сервісами;
- функції на кшталт fetch, proxy або download.
Наприклад, небезпечний код може виглядати дуже просто:
url = params[:url]
response = HTTP.get(url)
Проблема тут не в HTTP.get як такому.
Проблема в тому, що користувач фактично отримав можливість визначати, куди сервер буде робити запит.
Чому просто перевірити URL недостатньо
Можна подумати, що достатньо заблокувати:
localhost
127.0.0.1
Але захист від SSRF складніший.
Існують різні представлення IP-адрес, DNS tricks, redirect-и та інші способи обійти наївну перевірку.
Наприклад, сервер може спочатку перевірити домен:
https://example.com
а потім отримати HTTP redirect на внутрішню адресу.
Тому перевіряти потрібно не лише URL, який користувач передав спочатку, а й кінцеву адресу, до якої фактично встановлюється з'єднання.
Як захиститися від SSRF
Найкращий захист - не дозволяти користувачу робити довільні server-side requests.
Якщо це неможливо, можна використовувати кілька рівнів захисту.
1. Allowlist
Замість blacklist краще дозволяти лише відомі домени:
api.example.com
images.example.com
а не намагатися перерахувати всі адреси, які потрібно заборонити.
2. Блокувати приватні адреси
Потрібно блокувати доступ до:
127.0.0.0/8
10.0.0.0/8
172.16.0.0/12
192.168.0.0/16
а також інших special-use та link-local адрес.
3. Контролювати redirect-и
Не варто дозволяти:
external-site.com
↓
internal-service
Перевірка має застосовуватися і до redirect-ів.
4. Обмежити протоколи
Якщо функції достатньо HTTP/HTTPS, не потрібно дозволяти довільні схеми на кшталт:
file://
gopher://
ftp://
5. Network isolation
Навіть якщо SSRF з'явиться, сервер не повинен мати можливості дістатися критичних внутрішніх систем.
Це хороший приклад принципу defense in depth: не покладатися на один-єдиний захисний механізм.
Blind SSRF
Існує ще один цікавий варіант - blind SSRF.
У цьому випадку сервер робить запит до ресурсу, але результат не повертається зловмиснику.
Наприклад:
Атакер
│
│ URL
▼
Web App
│
│ request
▼
Internal Service
Зловмисник не бачить response, але все одно може визначити, що запит відбувся, за непрямими ознаками.
Наприклад, сервер може звернутися до контрольованого зловмисником endpoint, а той побачить вхідний запит у своїх логах.
Blind SSRF складніше експлуатувати, але вона все одно може бути серйозною проблемою.
SSRF - це не просто "можна зробити запит"
Основна небезпека SSRF полягає в різниці між тим, що може бачити користувач, і тим, що може бачити сервер.
Користувач може мати доступ лише до:
Internet
а сервер - до:
Internet
+
Internal network
+
localhost
+
Cloud metadata
+
Private APIs
SSRF дозволяє атакеру використати ці додаткові права сервера.
Тому будь-яка функція виду:
"Передай мені URL, а я сам його завантажу"
повинна розглядатися як потенційна SSRF attack surface.
Коротко: SSRF - це ситуація, коли атакер змушує ваш сервер робити мережеві запити від свого імені. І чим більше внутрішніх ресурсів доступно серверу, тим серйознішими можуть бути наслідки такої вразливості.