codecamp

Node.js 文件操作

1.3.1 【必须】限定文件操作的后缀范围

  • 按业务需求,使用白名单限定后缀范围。

1.3.2 【必须】校验并限定文件路径范围

  • 应固定上传、访问文件的路径。若需要拼接外部可控变量值,检查是否包含...路径穿越字符。如存在,应拒绝。
  • 使用fs模块下的函数方法时,应对第一个参数即路径部分做校验,检查是否包含路径穿越字符...。涉及方法包括但不限于:fs.truncatefs.truncateSyncfs.chownfs.chownSyncfs.lchownfs.lchownSyncfs.statfs.lchmodSyncfs.lstatfs.statSyncfs.lstatSyncfs.readlinkfs.unlinkfs.unlinkSyncfs.rmdirfs.rmdirSyncfs.mkdirfs.mkdirSyncfs.readdirfs.readdirSyncfs.openSyncfs.openfs.createReadStreamfs.createWriteStream
  • 使用express框架的sendFile方法时,应对第一个参数即路径部分做校验,检查是否包含路径穿越字符...
  • 校验时,应使用path模块处理前的路径参数值,或判断处理过后的路径是否穿越出了当前工作目录。涉及方法包括但不限于:path.resolvepath.joinpath.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。
  • 访问敏感资源文件时,应进行权限控制。默认情况下,仅用户可查看、操作自身敏感资源文件。
  • 图片类文件应添加业务水印,表明该图片仅可用于当前业务使用。
Node.js 执行命令
Node.js 网络请求
温馨提示
下载编程狮App,免费阅读超1000+编程语言教程
取消
确定
目录

关闭

MIP.setData({ 'pageTheme' : getCookie('pageTheme') || {'day':true, 'night':false}, 'pageFontSize' : getCookie('pageFontSize') || 20 }); MIP.watch('pageTheme', function(newValue){ setCookie('pageTheme', JSON.stringify(newValue)) }); MIP.watch('pageFontSize', function(newValue){ setCookie('pageFontSize', newValue) }); function setCookie(name, value){ var days = 1; var exp = new Date(); exp.setTime(exp.getTime() + days*24*60*60*1000); document.cookie = name + '=' + value + ';expires=' + exp.toUTCString(); } function getCookie(name){ var reg = new RegExp('(^| )' + name + '=([^;]*)(;|$)'); return document.cookie.match(reg) ? JSON.parse(document.cookie.match(reg)[2]) : null; }