In this lesson, you will learn how to safely resolve file paths to ensure your application remains protected against directory traversal vulnerabilities.
When handling user-provided file paths, it is tempting to simply concatenate strings. However, attackers can exploit this by using sequences like ../ to escape your intended directory—a common security flaw known as a directory traversal attack. Because Node.js runs on various operating systems (like Windows and Linux), handling path delimiters manually is error-prone.
The Strategy: Normalization and Anchoring
To mitigate this, you must treat all user input as untrusted. The strategy involves two steps: Normalization and Anchoring.
- Normalization: Use
path.normalize()to resolve unnecessary separators and..segments within a string. This ensures the path is clean, but it doesn't prevent escaping the root. - Anchoring: Use
path.join()orpath.resolve()combined withpath.relative()to verify the final path stays within a safe, designated "base" directory.
Here is how you can implement a safe resolution check:
const path = require('path');
function getSafeFilePath(userInput, baseDir) {
// Resolve the absolute path
const safeBase = path.resolve(baseDir);
const targetPath = path.resolve(safeBase, userInput);
// Ensure the target path starts with the base directory
if (!targetPath.startsWith(safeBase)) {
throw new Error('Access denied: Potential directory traversal attempt.');
}
return targetPath;
}
// Example usage
// Even if userInput is "../../etc/passwd", the check will fail.
const file = getSafeFilePath('user-files/my-data.txt', './uploads');
By resolving the absolute path of both your base directory and the user input, you create a point of comparison. If the resulting path does not start with your safeBase, you know the user attempted to navigate outside the authorized boundaries. Never trust user input to navigate the file system directly; always anchor it to a safe root and verify the prefix before performing any I/O operations.
Key Takeaway: Always normalize paths and verify that the resulting absolute path remains prefixed by your intended base directory to prevent unauthorized file access.