105 lines
2.8 KiB
JavaScript
105 lines
2.8 KiB
JavaScript
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 };
|