const config = require('../config'); const logger = require('../utils/logger'); /** * 路径安全验证 - 白名单机制 * 只允许访问预设目录 */ function validatePath(path) { if (!path || typeof path !== 'string') { throw new Error('路径不能为空'); } // 规范化路径(防止 ../ 穿越) const normalized = normalizePath(path); // 检查是否在白名单内 const allowed = config.security.whitelistDirs.some(dir => { const normalizedDir = normalizePath(dir); return normalized === normalizedDir || normalized.startsWith(normalizedDir + '/'); }); if (!allowed) { logger.warn(`[安全] 路径被拒绝: ${path} (规范化: ${normalized})`); throw new Error(`路径不在白名单内: ${path}。允许的目录: ${config.security.whitelistDirs.join(', ')}`); } return normalized; } /** * 路径规范化(防止路径穿越攻击) */ function normalizePath(path) { // 移除多余的斜杠 let normalized = path.replace(/\/+/g, '/'); // 解析 .. 和 . const parts = normalized.split('/'); const result = []; for (const part of parts) { if (part === '' || part === '.') continue; if (part === '..') { result.pop(); // 回退一级 } else { result.push(part); } } return '/' + result.join('/'); } /** * 命令安全验证 * 防止命令注入 */ function validateCommand(command) { if (!command || typeof command !== 'string') { throw new Error('命令不能为空'); } // 禁止的危险字符和模式 const dangerousPatterns = [ /;/, // 命令分隔 /&&/, // 命令链接(允许在预设命令中) /\|\|/, // 或链接 /\$\(/, // 命令替换 /`/, // 反引号命令替换 />\s*\//, // 重定向到绝对路径 /rm\s+-rf/, // 危险删除 /rm\s+-r/, // 递归删除 /dd\s+if=/, // dd 命令 /mkfs/, // 格式化 /shutdown/, // 关机 /reboot/, // 重启 /curl.*\|/, // 管道执行 /wget.*\|/, // 管道执行 ]; for (const pattern of dangerousPatterns) { if (pattern.test(command)) { logger.warn(`[安全] 危险命令被拒绝: ${command}`); throw new Error(`命令包含危险模式,已被拒绝: ${command}`); } } return command; } /** * 验证文件名安全性 */ function validateFileName(fileName) { if (!fileName || typeof fileName !== 'string') { throw new Error('文件名不能为空'); } // 禁止路径分隔符和特殊字符 if (/[/\\:*?"<>|]/.test(fileName)) { throw new Error(`文件名包含非法字符: ${fileName}`); } if (fileName.includes('..')) { throw new Error(`文件名包含路径穿越: ${fileName}`); } return fileName; } module.exports = { validatePath, validateCommand, validateFileName, normalizePath };