← Назад к вопросам

Что такое Path Traversal уязвимость и как её предотвратить?

2.8 Senior🔥 251 комментариев
#Node.js и JavaScript#Безопасность

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI30 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Path Traversal уязвимость

Path Traversal (Directory Traversal) - это тип уязвимости, при которой злоумышленник может получить доступ к файлам и директориям, расположенным за пределами предполагаемой корневой директории веб-приложения. Атака использует недостаточную валидацию пользовательского ввода при формировании путей к файлам.

Как работает атака

Злоумышленник манипулирует параметрами запроса, используя специальные последовательности вроде ../ для выхода за пределы разрешённой директории:

// Уязвимый код
app.get("/files", (req, res) => {
  const fileName = req.query.name;
  const filePath = path.join(__dirname, "uploads", fileName);
  res.sendFile(filePath); // опасно!
});

// Запрос: GET /files?name=../../../etc/passwd
// Результат: доступ к системному файлу

Основные векторы атаки

  • Прямой обход: ../../etc/passwd
  • URL-кодирование: %2e%2e%2f вместо ../
  • Двойное кодирование: %252e%252e%252f
  • Null-byte инъекция: ../../etc/passwd%00.png (в старых версиях Node.js)
  • Unicode/UTF-8: использование символов типа ..%c0%af

Методы предотвращения

1. Нормализация и валидация пути:

import path from "path";

const UPLOADS_DIR = path.resolve(__dirname, "uploads");

app.get("/files", (req, res) => {
  const fileName = req.query.name as string;
  const resolvedPath = path.resolve(UPLOADS_DIR, fileName);

  // Проверяем, что итоговый путь внутри разрешённой директории
  if (!resolvedPath.startsWith(UPLOADS_DIR)) {
    return res.status(403).json({ error: "Access denied" });
  }

  res.sendFile(resolvedPath);
});

2. Белый список файлов:

const allowedFiles = new Set(["report.pdf", "image.png", "data.csv"]);

app.get("/files", (req, res) => {
  const fileName = path.basename(req.query.name as string);
  if (!allowedFiles.has(fileName)) {
    return res.status(404).json({ error: "File not found" });
  }
  res.sendFile(path.join(UPLOADS_DIR, fileName));
});

3. Использование path.basename для извлечения только имени файла без пути:

const safeName = path.basename(userInput); // "../../../etc/passwd" -> "passwd"

4. Дополнительные меры защиты:

  • chroot или контейнеризация для ограничения файловой системы
  • Запуск процесса с минимальными привилегиями
  • Использование middleware вроде helmet для заголовков безопасности
  • Регулярные аудиты с инструментами типа Snyk, npm audit
  • Запрет символических ссылок в директории загрузок (lstat для проверки)

Защита в популярных фреймворках

В Express.js статические файлы через express.static() уже защищены от path traversal. Но при ручной работе с fs.readFile или res.sendFile разработчик должен сам обеспечить валидацию.

В NestJS рекомендуется использовать StreamableFile и @Res() декоратор с предварительной проверкой пути через path.resolve + проверку startsWith.

Что такое Path Traversal уязвимость и как её предотвратить? | PrepBro