feat: 升级至 v0.3.16 — 工单修复 51 项 + 审查修复 30 项(安全加固/适配器/工具系统/数据层/前端)
This commit is contained in:
@@ -157,13 +157,32 @@ export class PolicyEngine {
|
||||
argsStr = String(args);
|
||||
}
|
||||
|
||||
// #14 修复: 深度递归扫描所有字符串字段值,防止 Unicode 转义/嵌套对象/字符串拼接绕过
|
||||
// 原 JSON.stringify 后整体正则匹配可被 \u0029 编码、嵌套对象伪装、正则注入等方式绕过
|
||||
// 现对每个字符串字段值单独匹配,同时保留整体 argsStr 兜底匹配
|
||||
const stringValues = this.deepScanStrings(args);
|
||||
|
||||
// v0.2.0: allowedPatterns 白名单校验 — 若定义了白名单,参数必须匹配其中之一
|
||||
// #14: 字段级匹配 + 整体兜底,任一匹配即通过
|
||||
if (policy.allowedPatterns && policy.allowedPatterns.length > 0) {
|
||||
let matchedAllowed = false;
|
||||
for (const pattern of policy.allowedPatterns) {
|
||||
if (pattern.test(argsStr)) {
|
||||
matchedAllowed = true;
|
||||
break;
|
||||
// 先做字段级匹配
|
||||
for (const val of stringValues) {
|
||||
for (const pattern of policy.allowedPatterns) {
|
||||
if (pattern.test(val)) {
|
||||
matchedAllowed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (matchedAllowed) break;
|
||||
}
|
||||
// 兜底:整体 argsStr 匹配
|
||||
if (!matchedAllowed) {
|
||||
for (const pattern of policy.allowedPatterns) {
|
||||
if (pattern.test(argsStr)) {
|
||||
matchedAllowed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!matchedAllowed) {
|
||||
@@ -176,7 +195,22 @@ export class PolicyEngine {
|
||||
}
|
||||
}
|
||||
|
||||
// #14 修复: deniedPatterns 字段级深度扫描 — 对每个字符串值单独匹配
|
||||
// 防止危险内容隐藏在嵌套对象或 Unicode 编码中绕过整体 stringify 匹配
|
||||
if (policy.deniedPatterns) {
|
||||
for (const val of stringValues) {
|
||||
for (const pattern of policy.deniedPatterns) {
|
||||
if (pattern.test(val)) {
|
||||
return {
|
||||
authorized: false,
|
||||
reason: 'Command blocked by security policy',
|
||||
level: policy.requiredLevel,
|
||||
requiresConfirmation: false,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
// 兜底:整体 argsStr 匹配(保留原有行为,捕获跨字段拼接的危险模式)
|
||||
for (const pattern of policy.deniedPatterns) {
|
||||
if (pattern.test(argsStr)) {
|
||||
return {
|
||||
@@ -264,4 +298,37 @@ export class PolicyEngine {
|
||||
|
||||
// v0.3.0 修复: cleanupFrequencyRecords 已删除 — checkFrequency 和 recordCall 已做内联清理,
|
||||
// 该方法属于死代码,删除以减少维护负担
|
||||
|
||||
/**
|
||||
* #14 修复: 深度递归扫描对象,提取所有字符串字段值
|
||||
*
|
||||
* 替代 JSON.stringify 后整体正则匹配的方式,防止:
|
||||
* - Unicode 转义绕过(\u0029 等编码)
|
||||
* - 嵌套对象伪装({a: {b: 'dangerous'}})
|
||||
* - 字符串拼接绕过('rm ' + '-rf /' 在 stringify 后是合法字符串)
|
||||
* - 正则注入(输入中包含正则元字符破坏匹配逻辑)
|
||||
*
|
||||
* @param obj 待扫描的对象
|
||||
* @returns 所有字符串字段值的数组
|
||||
*/
|
||||
// 审查修复: 添加 visited Set 参数防止循环引用导致无限递归栈溢出
|
||||
private deepScanStrings(obj: unknown, visited: Set<unknown> = new Set()): string[] {
|
||||
const results: string[] = [];
|
||||
if (typeof obj === 'string') {
|
||||
results.push(obj);
|
||||
} else if (Array.isArray(obj)) {
|
||||
if (visited.has(obj)) return results;
|
||||
visited.add(obj);
|
||||
for (const item of obj) {
|
||||
results.push(...this.deepScanStrings(item, visited));
|
||||
}
|
||||
} else if (obj && typeof obj === 'object') {
|
||||
if (visited.has(obj)) return results;
|
||||
visited.add(obj);
|
||||
for (const v of Object.values(obj)) {
|
||||
results.push(...this.deepScanStrings(v, visited));
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user