flawopen.com/Path Traversal/Node.js path.join()
¿Node.js path.join() evita Path Traversal?
No. path.join() normaliza los segmentos, pero no impide que .. salga del directorio previsto. Resuelve la ruta candidata con respecto a la base y verifica que la ruta relativa permanezca dentro. Esta comprobación léxica no contiene los symlinks del sistema de archivos.
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");
}
Por qué path.join() no basta
path.join() combina segmentos con el separador de la plataforma y normaliza el resultado. La normalización no rechaza .., que es válido en muchas rutas. Unir ../../etc/passwd a una base aún puede producir una ruta externa; join() no verifica la contención.
Preguntas frecuentes
path.normalize() resuelve segmentos .. y . en la cadena, pero no verifica que el resultado permanezca dentro de una base permitida. Compara path.relative(base, resolved) y rechaza un resultado vacío si se requiere un archivo, .., un prefijo .. seguido de path.sep o un resultado relativo absoluto.
No. path.resolve() y path.relative() comparan cadenas de ruta; no siguen symlinks del sistema de archivos. Si un atacante puede crear o reemplazar symlinks bajo la base, valida el destino real y usa operaciones que eviten una carrera entre comprobación y uso. Restringe los permisos de escritura del árbol cuando sea posible.