flawopen.com/path-traversal/Javascript
How naive path.join allows directory traversal in Express/Node.js, and how to enforce directory boundary checks with path.resolve and path.sep.
设想一家酒店的房卡扫描锁原本只允许开启二楼的客房。如果客人在门禁键盘上输入 '../../master-safe',有缺陷的门锁就会跳出当前楼道,直接打开酒店经理办公室的主保险箱。
Web Application SecurityCWE-918.CWE-918CWE-918):Standard Common Weakness Enumeration classification for path-traversal-javascript.Defense-in-Depth应用程序接口通过 HTTP 参数接收用户指定的文件名、报告路径或静态资源标识。
攻击者在文件名参数中注入相对路径遍历符号(如 '../', '..%2f')或绝对路径覆盖。
后端直接将不可信输入与基础目录拼接,未进行规范化绝对路径解析(Canonicalization)与边界校验。
系统运行时打开并回传敏感配置文件(如 /etc/passwd、源码凭证、环境变量密钥),造成数据外泄。
// VULNERABLE: path.join allows directory breakout
const express = require('express');
const path = require('path');
const fs = require('fs');
const app = express();
const PUBLIC_DIR = path.join(__dirname, 'public');
app.get('/download', (req, res) => {
// Attacker input: "../../etc/passwd"
const targetFile = path.join(PUBLIC_DIR, req.query.file);
// Directly pipes arbitrary system file to response!
res.sendFile(targetFile);
});
// HARDENED: Canonicalize path and assert prefix with directory separator
const express = require('express');
const path = require('path');
const fs = require('fs');
const app = express();
const PUBLIC_DIR = path.resolve(__dirname, 'public');
app.get('/download', (req, res) => {
const userInput = req.query.file;
if (!userInput || typeof userInput !== 'string') {
return res.status(400).send('Invalid file parameter');
}
// 1. Resolve to absolute path
const safePath = path.resolve(PUBLIC_DIR, userInput);
// 2. Strict boundary check: must start with base folder + separator
if (!safePath.startsWith(PUBLIC_DIR + path.sep)) {
return res.status(403).send('Forbidden: Path Traversal detected');
}
// 3. Verify file exists and is a regular file
fs.stat(safePath, (err, stats) => {
if (err || !stats.isFile()) return res.status(404).send('File not found');
res.sendFile(safePath);
});
});
path.resolve()。express.static() with dotfiles: 'ignore' for static file serving。