Node.js 文件操作
1.3.1 【必须】限定文件操作的后缀范围
- 按业务需求,使用白名单限定后缀范围。
1.3.2 【必须】校验并限定文件路径范围
- 应固定上传、访问文件的路径。若需要拼接外部可控变量值,检查是否包含
..、.路径穿越字符。如存在,应拒绝。 - 使用
fs模块下的函数方法时,应对第一个参数即路径部分做校验,检查是否包含路径穿越字符.或..。涉及方法包括但不限于:fs.truncate、fs.truncateSync、fs.chown、fs.chownSync、fs.lchown、fs.lchownSync、fs.stat、fs.lchmodSync、fs.lstat、fs.statSync、fs.lstatSync、fs.readlink、fs.unlink、fs.unlinkSync、fs.rmdir、fs.rmdirSync、fs.mkdir、fs.mkdirSync、fs.readdir、fs.readdirSync、fs.openSync、fs.open、fs.createReadStream、fs.createWriteStream - 使用express框架的
sendFile方法时,应对第一个参数即路径部分做校验,检查是否包含路径穿越字符.或.. - 校验时,应使用
path模块处理前的路径参数值,或判断处理过后的路径是否穿越出了当前工作目录。涉及方法包括但不限于:path.resolve、path.join、path.normalize等
const fs = require("fs");
const path = require("path");
let filename = req.query.ufile;
let root = '/data/ufile';
// bad:未检查文件名/路径
fs.readFile(root + filename, (err, data) => {
if (err) {
return console.error(err);
}
console.log(`异步读取: ${data.toString()}`);
});
// bad:使用path处理过后的路径参数值做校验,仍可能有路径穿越风险
filename = path.join(root, filename);
if (filename.indexOf("..") < 0) {
fs.readFile(filename, (err, data) => {
if (err) {
return console.error(err);
}
console.log(data.toString());
});
};
// good:检查了文件名/路径,是否包含路径穿越字符
if (filename.indexOf("..") < 0) {
filename = path.join(root, filename);
fs.readFile(filename, (err, data) => {
if (err) {
return console.error(err);
}
console.log(data.toString());
});
};
1.3.3 【必须】安全地处理上传文件名
- 将上传文件重命名为16位以上的随机字符串保存。
- 如需原样保留文件名,应检查是否包含
..、.路径穿越字符。如存在,应拒绝。
1.3.4 【必须】敏感资源文件,应有加密、鉴权和水印等加固措施
- 用户上传的
身份证、银行卡等图片,属敏感资源文件,应采取安全加固。 - 指向此类文件的URL,应保证不可预测性;同时,确保无接口会批量展示此类资源的URL。
- 访问敏感资源文件时,应进行权限控制。默认情况下,仅用户可查看、操作自身敏感资源文件。
- 图片类文件应添加业务水印,表明该图片仅可用于当前业务使用。