应禁用动态require路径拼接,优先采用预定义映射表或静态导入+条件分支;若必须拼接,须限定根目录、归一化路径并校验是否越界及是否为文件;上传场景需剥离路径、校验后缀、重命名后存入固定目录。

直接用用户输入拼接 require() 路径是高危操作,CommonJS 本身不提供路径校验机制,必须由开发者在调用前做严格控制。
只允许白名单内的模块名
避免拼接任意路径,改用预定义映射表。用户只传标识符(如 "report"),后端查表得到安全路径:
- 建立配置对象:
const MODULE_MAP = { report: './lib/reports/generate.js', dashboard: './lib/ui/dashboard.js' }; - 从请求中提取键名,仅限字母数字和下划线:
const key = input.replace(/[^a-z0-9_]/gi, ''); - 检查是否存在且为字符串:
if (!MODULE_MAP[key] || typeof MODULE_MAP[key] !== 'string') throw new Error('Invalid module'); - 再执行:
require(MODULE_MAP[key]);
若必须拼接路径,先规范化再比对根目录
Node.js 提供 path.resolve() 和 path.normalize(),但它们不能替代校验。关键步骤是:
详细的 Three.js 3D 图形参考,涵盖场景设置、相机、几何体、材质、光照、动画、控制器、加载器、数学工具和调试。
- 设定合法根目录:
const ROOT_DIR = path.join(__dirname, 'allowed_modules'); - 拼接并归一化:
const unsafePath = path.join(ROOT_DIR, userInput); const safePath = path.normalize(unsafePath); - 验证是否仍在根内:
if (!safePath.startsWith(ROOT_DIR + path.sep)) throw new Error('Path traversal blocked'); - 额外检查是否为文件(非目录):
if (!fs.statSync(safePath).isFile()) throw new Error('Not a valid module file');
禁用动态 require,改用静态导入 + 条件分支
最稳妥的方式是放弃运行时拼接。把可能加载的模块全部静态引入,用逻辑判断选择:
立即学习“Java免费学习笔记(深入)”;
const reportModule = require('./lib/reports/generate.js');const dashboardModule = require('./lib/ui/dashboard.js');- 根据参数决定调用哪个:
if (type === 'report') return reportModule.run(); - 这样完全消除路径解析环节,也利于构建工具分析和 tree-shaking。
上传或配置类场景:必须剥离路径再重命名
如果用户能指定“模块名”实则对应上传的 JS 文件,绝不能信任原始文件名:
- 用
path.basename()提取文件名,丢弃所有路径信息; - 校验后缀是否为
.js,并拒绝.、..、空字符串; - 生成唯一哈希名:
const safeName = `${Date.now()}-${crypto.randomUUID()}.js`; - 保存到固定子目录,再
require()绝对路径。

















