feat: 升级至 v0.3.16 — 工单修复 51 项 + 审查修复 30 项(安全加固/适配器/工具系统/数据层/前端)
This commit is contained in:
@@ -42,16 +42,17 @@ export class PromptInjectionDefender {
|
||||
private static INJECTION_PATTERNS: InjectionPattern[] = [
|
||||
// === HIGH 危险:直接越狱/忽略指令 ===
|
||||
// v0.3.0 修复:在关键词间允许可选限定词(the/any/all/these/those/your 等),防止 "ignore the previous instructions" 绕过
|
||||
{ pattern: /ignore\s+(?:(?:the|all|any|these|those|your|above)\s+)*(?:previous|above|prior)\s+(?:(?:the|your|all)\s+)*(?:instructions?|commands?|directives?|rules?)/i, severity: 'high' },
|
||||
{ pattern: /forget\s+(?:(?:everything|all|the|your|above|prior)\s+)+/i, severity: 'high' },
|
||||
{ pattern: /override\s+(?:(?:the|your|all|any)\s+)+/i, severity: 'high' },
|
||||
{ pattern: /JAILBREAK/i, severity: 'high' },
|
||||
{ pattern: /DAN\s*[:\[]/i, severity: 'high' },
|
||||
{ pattern: /(?:enable|turn\s+on|activate)\s+(?:(?:the|your)\s+)*(?:developer|debug|root|admin)\s+mode/i, severity: 'high' },
|
||||
{ pattern: /(?:disable|turn\s+off|bypass)\s+(?:(?:the|your|all|any)\s+)*(?:safety|security|filter|guard|defense|restrictions?)/i, severity: 'high' },
|
||||
{ pattern: /(?:send|transmit|exfiltrate|upload)\s+(?:(?:your|the|all|any)\s+)*(?:data|memory|context|secrets?)/i, severity: 'high' },
|
||||
{ pattern: /(?:you\s+are|act\s+as|pretend\s+to\s+be)\s+(?:a|an)\s+(?:unrestricted|unfiltered|unlimited|free)/i, severity: 'high' },
|
||||
{ pattern: /(?:in|under)\s+(?:(?:the|a)\s+)*(?:developer|unrestricted|jailbreak|god)\s+mode/i, severity: 'high' },
|
||||
// #15 修复: 添加 \b 单词边界,防止 "Xignore previous instructions" / "ignore previous instructionss" 等前后缀绕过
|
||||
{ pattern: /\bignore\s+(?:(?:the|all|any|these|those|your|above)\s+)*(?:previous|above|prior)\s+(?:(?:the|your|all)\s+)*(?:instructions?|commands?|directives?|rules?)\b/i, severity: 'high' },
|
||||
{ pattern: /\bforget\s+(?:(?:everything|all|the|your|above|prior)\s+)+/i, severity: 'high' },
|
||||
{ pattern: /\boverride\s+(?:(?:the|your|all|any)\s+)+/i, severity: 'high' },
|
||||
{ pattern: /\bJAILBREAK\b/i, severity: 'high' },
|
||||
{ pattern: /\bDAN\s*[:\[]/i, severity: 'high' },
|
||||
{ pattern: /\b(?:enable|turn\s+on|activate)\s+(?:(?:the|your)\s+)*(?:developer|debug|root|admin)\s+mode\b/i, severity: 'high' },
|
||||
{ pattern: /\b(?:disable|turn\s+off|bypass)\s+(?:(?:the|your|all|any)\s+)*(?:safety|security|filter|guard|defense|restrictions?)\b/i, severity: 'high' },
|
||||
{ pattern: /\b(?:send|transmit|exfiltrate|upload)\s+(?:(?:your|the|all|any)\s+)*(?:data|memory|context|secrets?)\b/i, severity: 'high' },
|
||||
{ pattern: /\b(?:you\s+are|act\s+as|pretend\s+to\s+be)\s+(?:a|an)\s+(?:unrestricted|unfiltered|unlimited|free)\b/i, severity: 'high' },
|
||||
{ pattern: /\b(?:in|under)\s+(?:(?:the|a)\s+)*(?:developer|unrestricted|jailbreak|god)\s+mode\b/i, severity: 'high' },
|
||||
// 中文高危
|
||||
{ pattern: /忽略(?:以上|之前|前面|上面|所有)(?:的)?(?:指令|指示|命令|说明|规则)/i, severity: 'high' },
|
||||
{ pattern: /忘记(?:之前|上面|所有)(?:的)?(?:内容|对话|指令)/i, severity: 'high' },
|
||||
@@ -59,15 +60,16 @@ export class PromptInjectionDefender {
|
||||
{ pattern: /无视(?:以上|之前|前面|所有)(?:的)?(?:指令|指示|命令|规则)/i, severity: 'high' },
|
||||
|
||||
// === MEDIUM 危险:角色扮演/权限提升/编码注入 ===
|
||||
{ pattern: /you\s+are\s+now/i, severity: 'medium' },
|
||||
{ pattern: /new\s+(instructions|directive|role|persona)/i, severity: 'medium' },
|
||||
{ pattern: /(show|display|print|output|reveal|tell\s+me)\s+(your|the)\s+(system\s+)?(prompt|instruction|directive)/i, severity: 'medium' },
|
||||
{ pattern: /(dump|echo|log|expose)\s+(your|the)\s+(context|memory|history)/i, severity: 'medium' },
|
||||
{ pattern: /pretend\s+(you\s+are|to\s+be)/i, severity: 'medium' },
|
||||
{ pattern: /act\s+as\s+(if\s+you\s+were|you're)/i, severity: 'medium' },
|
||||
{ pattern: /(?:grant|give)\s+(me|you|us)\s+(admin|root|sudo|super)/i, severity: 'medium' },
|
||||
{ pattern: /base64\s*:?\s*[A-Za-z0-9+/=]{20,}/i, severity: 'medium' },
|
||||
{ pattern: /eval\s*\(\s*atob\s*\(/i, severity: 'medium' },
|
||||
// #15 修复: 英文关键词模式添加 \b 单词边界
|
||||
{ pattern: /\byou\s+are\s+now\b/i, severity: 'medium' },
|
||||
{ pattern: /\bnew\s+(instructions|directive|role|persona)\b/i, severity: 'medium' },
|
||||
{ pattern: /\b(show|display|print|output|reveal|tell\s+me)\s+(your|the)\s+(system\s+)?(prompt|instruction|directive)\b/i, severity: 'medium' },
|
||||
{ pattern: /\b(dump|echo|log|expose)\s+(your|the)\s+(context|memory|history)\b/i, severity: 'medium' },
|
||||
{ pattern: /\bpretend\s+(you\s+are|to\s+be)\b/i, severity: 'medium' },
|
||||
{ pattern: /\bact\s+as\s+(if\s+you\s+were|you're)\b/i, severity: 'medium' },
|
||||
{ pattern: /\b(?:grant|give)\s+(me|you|us)\s+(admin|root|sudo|super)\b/i, severity: 'medium' },
|
||||
{ pattern: /\bbase64\s*:?\s*[A-Za-z0-9+/=]{20,}/i, severity: 'medium' },
|
||||
{ pattern: /\beval\s*\(\s*atob\s*\(/i, severity: 'medium' },
|
||||
{ pattern: /\\x[0-9a-f]{2}\\x[0-9a-f]{2}\\x[0-9a-f]{2}/i, severity: 'medium' },
|
||||
{ pattern: /\\u[0-9a-f]{4}\\u[0-9a-f]{4}/i, severity: 'medium' },
|
||||
// 中文中危
|
||||
@@ -103,11 +105,17 @@ export class PromptInjectionDefender {
|
||||
recommendation: 'PASS: No injection patterns detected',
|
||||
};
|
||||
}
|
||||
|
||||
// #16 修复: Unicode 归一化 + 移除零宽字符,防止同形字符与零宽字符绕过
|
||||
// 攻击示例:іgnore (西里尔 і)、ignore\u200bprevious (零宽空格)、ignore\u00adprevious (软连字符)
|
||||
// NFKC 归一化将兼容等价字符统一为规范形式,零宽字符移除后关键词检测可正常工作
|
||||
const normalized = this.normalizeForDetection(input);
|
||||
|
||||
const findings: InjectionFinding[] = [];
|
||||
let riskScore = 0;
|
||||
|
||||
for (const { pattern, severity } of PromptInjectionDefender.INJECTION_PATTERNS) {
|
||||
const matches = input.match(pattern);
|
||||
const matches = normalized.match(pattern);
|
||||
if (matches) {
|
||||
findings.push({
|
||||
pattern: pattern.source,
|
||||
@@ -118,6 +126,17 @@ export class PromptInjectionDefender {
|
||||
}
|
||||
}
|
||||
|
||||
// #16 新增: 检测可疑 Unicode 混合脚本(拉丁 + 西里尔/希腊),提高风险分数
|
||||
// 同形字符攻击通常需要混用拉丁与西里尔/希腊字母,正常输入很少混用
|
||||
if (this.hasMixedScripts(input)) {
|
||||
findings.push({
|
||||
pattern: 'unicode:mixed_scripts',
|
||||
matched: 'Mixed Latin/Cyrillic/Greek scripts detected (potential homoglyph attack)',
|
||||
severity: 'medium',
|
||||
});
|
||||
riskScore += 3;
|
||||
}
|
||||
|
||||
return {
|
||||
isInjection: findings.length > 0,
|
||||
riskScore: Math.min(10, riskScore),
|
||||
@@ -148,21 +167,25 @@ export class PromptInjectionDefender {
|
||||
recommendation: 'PASS: No injection patterns detected',
|
||||
};
|
||||
}
|
||||
|
||||
// #16 修复: 语义检测同样使用归一化文本,防止 Unicode 绕过
|
||||
const normalized = this.normalizeForDetection(input);
|
||||
|
||||
const findings: InjectionFinding[] = [];
|
||||
let riskScore = 0;
|
||||
|
||||
// 1. 先执行正则快速检测
|
||||
// 1. 先执行正则快速检测(detect 内部已做归一化)
|
||||
const regexResult = this.detect(input);
|
||||
findings.push(...regexResult.findings);
|
||||
riskScore += regexResult.riskScore;
|
||||
|
||||
// 2. 语义级检测
|
||||
// 2. 语义级检测(使用归一化文本)
|
||||
// 2a. 指令性动词密度检测
|
||||
const imperativeCheck = this.checkImperativeDensity(input);
|
||||
const imperativeCheck = this.checkImperativeDensity(normalized);
|
||||
if (imperativeCheck.isSuspicious) {
|
||||
findings.push({
|
||||
pattern: 'semantic:imperative_density',
|
||||
matched: `${imperativeCheck.count} imperative verbs in ${input.length} chars`,
|
||||
matched: `${imperativeCheck.count} imperative verbs in ${normalized.length} chars`,
|
||||
severity: 'medium',
|
||||
});
|
||||
riskScore += 2;
|
||||
@@ -170,7 +193,7 @@ export class PromptInjectionDefender {
|
||||
|
||||
// 2b. 角色边界异常检测
|
||||
if (context) {
|
||||
const roleAnomaly = this.checkRoleBoundary(input, context);
|
||||
const roleAnomaly = this.checkRoleBoundary(normalized, context);
|
||||
if (roleAnomaly) {
|
||||
findings.push(roleAnomaly);
|
||||
riskScore += 3;
|
||||
@@ -178,14 +201,14 @@ export class PromptInjectionDefender {
|
||||
}
|
||||
|
||||
// 2c. 结构化分隔符嵌套检测
|
||||
const nestedFinding = this.checkNestedDelimiters(input);
|
||||
const nestedFinding = this.checkNestedDelimiters(normalized);
|
||||
if (nestedFinding) {
|
||||
findings.push(nestedFinding);
|
||||
riskScore += 2;
|
||||
}
|
||||
|
||||
// 2d. 隐式指令检测(通过疑问句伪装指令)
|
||||
const implicitFinding = this.checkImplicitInstructions(input);
|
||||
const implicitFinding = this.checkImplicitInstructions(normalized);
|
||||
if (implicitFinding) {
|
||||
findings.push(implicitFinding);
|
||||
riskScore += 1;
|
||||
@@ -199,6 +222,42 @@ export class PromptInjectionDefender {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* #16 修复: Unicode 归一化与零宽字符清理
|
||||
*
|
||||
* 1. NFKC 归一化:将兼容等价字符(如西里尔 і → 拉丁 i)统一为规范形式
|
||||
* 2. 移除零宽字符:零宽空格(U+200B)、零宽连字符(U+200C)、零宽不连字符(U+200D)、
|
||||
* 软连字符(U+00AD)、BOM(U+FEFF)
|
||||
*
|
||||
* 这些字符在视觉上不可见,但会破坏正则关键词匹配,被用于绕过注入检测
|
||||
*/
|
||||
private normalizeForDetection(input: string): string {
|
||||
return input
|
||||
.normalize('NFKC')
|
||||
.replace(/[\u200b\u200c\u200d\u00ad\ufeff]/g, '');
|
||||
}
|
||||
|
||||
/**
|
||||
* #16 新增: 检测可疑 Unicode 混合脚本
|
||||
*
|
||||
* 同形字符攻击通常混用拉丁与西里尔/希腊字母(如 іgnore 中 і 是西里尔字母)。
|
||||
* 正常技术输入很少混用这些脚本,检测到混用时提高风险分数。
|
||||
* NFKC 归一化可能无法完全消除所有同形字符,因此混合脚本检测作为补充手段。
|
||||
*/
|
||||
// 审查修复: 改为统计各脚本字符数量,只有当非主导脚本的字符总数占比 > 30% 时才触发,
|
||||
// 避免正常多语言输入(如 "Hello, Привет")误报
|
||||
private hasMixedScripts(text: string): boolean {
|
||||
const latin = (text.match(/[\u0000-\u007f]/g) || []).length;
|
||||
const cyrillic = (text.match(/[\u0400-\u04ff]/g) || []).length;
|
||||
const greek = (text.match(/[\u0370-\u03ff]/g) || []).length;
|
||||
const total = latin + cyrillic + greek;
|
||||
if (total < 10) return false; // 文本太短不检测
|
||||
const max = Math.max(latin, cyrillic, greek);
|
||||
const minorityRatio = (total - max) / total;
|
||||
// 审查修复: 只有少数脚本占比 > 30% 时才触发,避免正常多语言输入误报
|
||||
return minorityRatio > 0.3;
|
||||
}
|
||||
|
||||
/**
|
||||
* 指令性动词密度检测
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user