ai-chatbot/lib/security/input-sanitizer.ts
Your Name a8abed6b5b
Some checks failed
Lint / build (20) (push) Has been cancelled
Playwright Tests / test (push) Has been cancelled
feat: 添加多层安全防护机制
- 添加速率限制中间件,防止API滥用和DDoS攻击
- 添加可疑请求检测,基于行为模式识别攻击
- 添加输入清理和验证,防止命令注入和XSS攻击
- 更新middleware.ts,集成所有安全功能
- 添加fail2ban安装脚本,防止SSH暴力破解
- 不依赖IP黑名单,适用于所有攻击者

安全功能:
- API速率限制:每分钟100次请求
- 认证速率限制:每分钟5次请求
- 自动检测可疑请求模式
- 输入清理和验证
- 详细的安全日志记录
2025-12-28 22:45:13 +08:00

125 lines
3.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 输入清理和验证工具
* 防止命令注入、XSS等攻击
*/
// 危险命令和关键词模式
const DANGEROUS_PATTERNS = [
// 命令执行
/[;&|`$(){}[\]]/g, // 命令分隔符
/\b(wget|curl|nc|netcat|bash|sh|python|perl|ruby|node)\s+/gi,
/\b(exec|eval|system|spawn|execSync|execFile)\s*\(/gi,
// 文件操作
/\.\.\//g, // 路径遍历
/\.\.\\/g, // Windows路径遍历
// 脚本执行
/<script[^>]*>/gi,
/javascript:/gi,
/on\w+\s*=/gi, // 事件处理器
// SQL注入模式(虽然我们使用ORM,但作为额外保护)
/('|(\\')|(--)|(;)|(\/\*)|(\*\/)|(\+)|(\%27)|(\%22))/gi,
// 命令注入常见模式
/\|\s*(bash|sh|nc|wget|curl)/gi,
/;\s*(wget|curl|nc|bash|sh)/gi,
/\$\s*\(/g, // $(command)
/`[^`]*`/g, // 反引号命令执行
];
/**
* 清理字符串,移除危险字符
*/
export function sanitizeString(input: string): string {
if (typeof input !== "string") {
return String(input);
}
let sanitized = input;
// 移除危险模式
for (const pattern of DANGEROUS_PATTERNS) {
sanitized = sanitized.replace(pattern, "");
}
// 移除控制字符
sanitized = sanitized.replace(/[\x00-\x1F\x7F]/g, "");
// 限制长度(防止DoS)
if (sanitized.length > 10000) {
sanitized = sanitized.substring(0, 10000);
}
return sanitized.trim();
}
/**
* 验证字符串是否包含危险内容
*/
export function containsDangerousContent(input: string): boolean {
if (typeof input !== "string") {
return false;
}
for (const pattern of DANGEROUS_PATTERNS) {
if (pattern.test(input)) {
return true;
}
}
return false;
}
/**
* 清理对象中的所有字符串值
*/
export function sanitizeObject<T extends Record<string, any>>(obj: T): T {
const sanitized = { ...obj };
for (const key in sanitized) {
if (typeof sanitized[key] === "string") {
sanitized[key] = sanitizeString(sanitized[key]) as T[Extract<keyof T, string>];
} else if (typeof sanitized[key] === "object" && sanitized[key] !== null) {
sanitized[key] = sanitizeObject(sanitized[key]) as T[Extract<keyof T, string>];
}
}
return sanitized;
}
/**
* 验证请求体
*/
export async function validateRequestBody(body: any): Promise<{
valid: boolean;
sanitized?: any;
errors?: string[];
}> {
const errors: string[] = [];
// 将body转换为字符串进行检查
const bodyString = typeof body === "string" ? body : JSON.stringify(body);
// 检查危险内容
if (containsDangerousContent(bodyString)) {
errors.push("Request body contains potentially dangerous content");
}
// 如果body是对象,清理它
let sanitized = body;
if (typeof body === "object" && body !== null) {
sanitized = sanitizeObject(body);
} else if (typeof body === "string") {
sanitized = sanitizeString(body);
}
return {
valid: errors.length === 0,
sanitized: errors.length === 0 ? sanitized : undefined,
errors: errors.length > 0 ? errors : undefined,
};
}