FlawOpen

flawopen.com/Path Traversal/Node.js path.join()

Защищает ли Node.js path.join() от Path Traversal?

Справочная страница
Краткий ответ

Нет. path.join() нормализует сегменты, но не мешает .. выйти за пределы целевого каталога. Разрешите кандидатный путь относительно базового и проверьте, что относительный путь остаётся внутри. Эта лексическая проверка не учитывает символические ссылки файловой системы.

ВСЁ ЕЩЁ УЯЗВИМО
const filePath = path.join(
  BASE_DIR, userFilename
);
// userFilename = "../../etc/passwd"
// still escapes BASE_DIR
ИСПРАВЛЕНО — лексическая проверка границ
const base = path.resolve(BASE_DIR);
const resolved = path.resolve(base, userFilename);
const relative = path.relative(base, resolved);

if (
  relative === '' ||
  relative === '..' ||
  relative.startsWith('..' + path.sep) ||
  path.isAbsolute(relative)
) {
  throw new Error("Invalid path");
}

Почему одного path.join() недостаточно

path.join() объединяет сегменты системным разделителем и нормализует результат. Нормализация не запрещает .., допустимый во многих путях. Объединение ../../etc/passwd с базой всё ещё может дать путь за её пределами; join() не проверяет границы.

Вопросы и ответы

Помогает ли path.normalize()?

path.normalize() разрешает сегменты .. и . в строке, но не проверяет, остаётся ли результат внутри разрешённой базы. Сравните path.relative(base, resolved) и отклоняйте пустой результат, если требуется файл, .., префикс .. с path.sep и абсолютный относительный результат.

Защищает ли эта проверка от выхода через symlink?

Нет. path.resolve() и path.relative() сравнивают строки и не переходят по символическим ссылкам файловой системы. Если атакующий может создавать или заменять ссылки внутри базы, проверяйте реальную цель и предотвращайте гонку между проверкой и использованием. По возможности ограничьте запись в дерево каталогов.

Источники

См. также Обход каталогов (CWE-22): как это работает и как предотвратить на любом языке — flawopen.com PHP include() и пути, заданные пользователем Защита от Path Traversal в Python os.path.join() Что такое уязвимость Zip Slip?