Bug2Lab · Secure Code · Java / File IO

Directory Traversal в скачивании логов

Эндпоинт отдаёт файл лога по имени. Атакующий подставляет ../../.. и скачивает системные файлы (например, /etc/passwd). Фикс — нормализовать путь и запрещать выход за пределы разрешённой директории.

1
Как выглядит атака
Атакующий вызывает:
/logs?file=../../../../etc/passwd
и получает содержимое системного файла.
GET /logs?file=../../../../etc/passwd
200 OK (text/plain)
root:x:0:0:root:/root:/bin/bash
dbuser:x:1001:1001:/home/dbuser:/bin/sh
...
2
Почему это стало возможным
Код просто делает new File("logs/"+fileParam) и читает то, что получилось. Никакой проверки, куда реально указывает путь.
Проблемный код
11@GetMapping("/logs")
12public String getLog(@RequestParam String file) throws IOException {
13 File f = new File("logs/" + file); // ❌ может быть ../../../etc/passwd
14 return Files.readString(f.toPath());
15}
3
Как это чинится правильно
Нормализуем путь и проверяем, что он остаётся внутри разрешённой директории logs/. Если вылезли выше — сразу 403.
Исправленный паттерн
11@GetMapping("/logs")
12public String getLog(@RequestParam String file) throws IOException {
13 Path base = Paths.get("logs").toAbsolutePath().normalize();
14 Path requested = base.resolve(file).normalize();
15 if (!requested.startsWith(base)) {
16 throw new ResponseStatusException(HttpStatus.FORBIDDEN,"Invalid path"); // ✅
17 }
18 return Files.readString(requested);
19}

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

Проверяем, что запрос с ../../ больше не возвращает 200 и не отдаёт системные файлы. Ожидаем 403.

#!/bin/bash
# traversal-check.sh
STATUS=$(curl -s -o /tmp/out.txt -w "%{http_code}" \
  "https://staging.example.internal/logs?file=../../../../etc/passwd")

if [ "$STATUS" = "200" ]; then
  echo "[BLOCK] Directory Traversal: можно читать системные файлы"
  exit 1
fi

echo "[OK] Запрещён выход за пределы logs/ (HTTP $STATUS)"
exit 0

Это гарантирует, что новый «просмотр логов» не станет окном в файловую систему.

Проверка пониманияГде корень проблемы?

Стандарт:никаких "отдай файл по имени, которое дал пользователь" без нормализации пути и белого списка директории.

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