Найдите уязвимость чтения файла по имени из запроса
Этот обработчик на Node.js отдаёт файл, чьё имя берётся из строки запроса. Определите уязвимость и как её эксплуатируют, затем опишите исправление.
Ограничения:
- считайте, что
query.fileNameполностью контролируется атакующим - предполагаемая директория —
./open-media/ - сосредоточьтесь на доступе к файловой системе, не на транспортной безопасности
const pathToFile = `./open-media/${query.fileName}`;
const file = fs.readFileSync(pathToFile, 'binary');
res.write(file, 'binary');
Определите причину.
Path traversal (обход каталога) — fileName склеивается в путь без проверки, поэтому ../ выходит за пределы open-media/ и читает произвольные файлы. Фикс: нормализовать итоговый путь и проверить, что он внутри базовой директории, либо белый список имён.
- ✗Считать, что фильтрация только расширения файла останавливает обход каталога
- ✗Полагаться на удаление подстроки '../' без нормализации итогового пути
- ✗Путать path traversal с XSS из-за наличия пользовательского ввода
- →Почему проверять нужно нормализованный путь, а не исходную строку?
- →Чем подход с белым списком имён надёжнее фильтрации '../'?
Уязвимость
fileName берётся из запроса и склеивается в путь без всякой проверки:
const pathToFile = `./open-media/${query.fileName}`;
Передав fileName = ../../etc/passwd, атакующий выходит из open-media/ вверх по дереву каталогов и читает любой доступный процессу файл — это path traversal (обход каталога).
Исправление
Нормализуйте итоговый путь и убедитесь, что он не выходит за пределы базовой директории:
const path = require('path');
const baseDir = path.resolve('./open-media');
const resolved = path.resolve(baseDir, query.fileName);
if (!resolved.startsWith(baseDir + path.sep)) {
res.statusCode = 400;
return res.end('Invalid file name');
}
const file = fs.readFileSync(resolved, 'binary');
res.write(file, 'binary');
⚠️ Проверять нужно именно нормализованный путь (path.resolve), а не исходную строку — иначе ....// и кодированные варианты обойдут наивный фильтр ../. Ещё надёжнее — сопоставлять запрос с белым списком известных имён файлов.