Bug2Lab · Secure Code · Java / Spring RestTemplate

SSRF: сервис ходит куда скажет пользователь

У нас есть эндпоинт-прокси: он скачивает указанный URL и отдаёт ответ клиенту. Проблема — мы не фильтруем, куда ходим. Злоумышленник может заставить сервис обращаться к внутренним адресам и вытягивать чувствительные данные.

1
Как выглядит атака
Атакующий вызывает:
/proxy?url=http://169.254.169.254/latest/meta-data/
Это метаданные облака (включая ключи доступа). Наш сервис, имея внутренний доступ, отдаёт их наружу.
GET /proxy?url=http://169.254.169.254/latest/meta-data/
200 OK
iam/security-credentials/app-role:
AccessKeyId=AKIA...PROD
SecretAccessKey=wJalrXUtnFEMI/K7MDENG/...PROD
2
Почему это стало возможным
Мы просто берём URL из параметра и ходим туда RestTemplate'ом. Никакого allowlist, никакой фильтрации внутренних адресов.
Проблемный код
12@GetMapping("/proxy")
13public String proxy(@RequestParam String url){
14 RestTemplate rt = new RestTemplate();
15 return rt.getForObject(url, String.class); // ❌ SSRF
16}
3
Как это чинится правильно
Разрешаем только ограниченный набор доменов (allowlist). Любые локальные / внутренние / облачные метаданные — блокируем.
Исправленный паттерн
12@GetMapping("/proxy")
13public String proxy(@RequestParam String url){
14 if (!url.startsWith("https://api.partner.example/")) {
15 throw new ResponseStatusException(HttpStatus.FORBIDDEN,"URL not allowed"); // ✅
16 }
17 return safeRestTemplate.getForObject(url, String.class);
18}

bug2regressРегрессионный тест

Тест пытается сходить через /proxy к внутреннему адресу 169.254.169.254. Если видим 200 — билд стопается. Ожидаем 403.

#!/bin/bash
# ssrf-check.sh
STATUS=$(curl -s -o /tmp/meta.txt -w "%{http_code}" \
  "https://staging.example.internal/proxy?url=http://169.254.169.254/latest/meta-data/")

if [ "$STATUS" = "200" ]; then
  echo "[BLOCK] SSRF: сервис даёт доступ к внутренним метаданным"
  exit 1
fi

echo "[OK] Внутренние адреса заблокированы (HTTP $STATUS)"
exit 0

Это закрывает класс атак, а не только конкретный URL.

Проверка пониманияЧто пошло не так?

Стандарт:прокси/превью/загрузка-URL никогда не должны ходить куда угодно. Только к заранее разрешённым хостам.

Теория (по желанию) SSRF = «сходи вот туда и принеси мне секреты из внутренней сети»