File size: 4,961 Bytes
89d813f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
"""
utils/security.py — LatentLearn 多维安全防护与敏感拦截层

功能:
  1. HTML 标签剥离(防止 XSS 脚本跨站攻击和注入污染)
  2. 递归清洗上传文档(防止注入文本对大模型及前端组件造成危害)
  3. 用户提问长度限制(防御 DoS 与 Token 爆满)
  4. 提示词注入拦截(秒级拦截绕过指令)
  5. 核心有毒/违规内容拦截(自残自杀、毒品枪支、网络诈骗、洗钱等)
"""

from __future__ import annotations

import re


# 1. 提示词注入攻击正则检测 (Prompt Injection Detection Patterns)
_INJECTION_PATTERNS = [
    r"ignore\s+(?:the\s+)?(?:previous|system|prior)\s+(?:instruction|prompt|rule|message|setting|directive)",
    r"forget\s+(?:the\s+)?(?:previous|system|prior)\s+(?:instruction|prompt|rule|message|setting|directive)",
    r"you\s+must\s+now\s+act\s+as",
    r"you\s+are\s+now\s+a\s+",
    r"bypass\s+(?:the\s+)?(?:system|security|filter|guardrail)",
    r"忽略(?:之前|先前的?)(?:指令|提示|规则|设定|说明|约束)",
    r"忘记(?:之前|先前的?)(?:指令|提示|规则|设定|说明|约束)",
    r"你现在(是|扮演|开始充当)\s*",
    r"解除(?:系统|安全)?限制",
    r"绕过(?:安全|系统|过滤)?",
    r"print\s+(?:your\s+)?system\s+(?:prompt|message|instruction)",
    r"输出(?:你?的?)?系统(?:提示词|指令|初始设置)"
]

# 2. 政治/黄暴/自残敏感词本地正则过滤 (Mild local keyword blacklist for toxic/illegal/self-harm queries)
_TOXIC_PATTERNS = [
    r"(?:自杀|自残|割腕|服毒|跳楼|不想活了|suicide|self-harm|kill\s+myself|end\s+my\s+life)",
    r"(?:吸毒|冰毒|海洛因|贩毒|大麻|meth|heroin|marijuana|drug\s+deal)",
    r"(?:制作炸弹|枪支制造|制造枪支|bomb\s+making|make\s+a\s+bomb|weapons\s+manufacturing)",
    r"(?:洗钱|诈骗|传销|money\s+laundering|scam|pyramid\s+scheme)"
]

# 3. HTML 标签剥离正则 (XSS Sanitizer)
_HTML_TAG_PATTERN = re.compile(r"<[^>]+>")


def sanitize_text(text: str | None) -> str | None:
    """过滤 HTML 标签以防止 XSS 攻击,保证文本纯净"""
    if not text:
        return text
    # 剥离所有 HTML 标签,只保留纯文本
    return _HTML_TAG_PATTERN.sub("", text).strip()


def sanitize_document(document: dict | None) -> dict | None:
    """
    递归清洗上传的学习文档:
      - 清洗标题 (title)
      - 清洗大章节正文 (content)
      - 递归清洗大纲小节结构 (structure)
    返回清洗后 100% 纯净、无 script/HTML 注入的安全文档字典。
    """
    if not document:
        return document
    
    sanitized = dict(document)
    
    if "title" in sanitized and isinstance(sanitized["title"], str):
        sanitized["title"] = sanitize_text(sanitized["title"])
        
    if "content" in sanitized and isinstance(sanitized["content"], str):
        sanitized["content"] = sanitize_text(sanitized["content"])
        
    if "structure" in sanitized and isinstance(sanitized["structure"], list):
        new_struct = []
        for sec in sanitized["structure"]:
            if isinstance(sec, dict):
                new_sec = dict(sec)
                if "title" in new_sec and isinstance(new_sec["title"], str):
                    new_sec["title"] = sanitize_text(new_sec["title"])
                if "content" in new_sec and isinstance(new_sec["content"], str):
                    new_sec["content"] = sanitize_text(new_sec["content"])
                new_struct.append(new_sec)
        sanitized["structure"] = new_struct
        
    return sanitized


def check_query_safety(query: str | None) -> tuple[bool, str | None]:
    """
    检查用户输入的安全健康状况。
    返回: (is_safe, error_hint)
    """
    if not query:
        return True, None

    # A. 限制输入长度,防止拒绝服务(DoS)或 Token 爆满
    if len(query) > 1000:
        return False, "Input query is too long (maximum 1000 characters). / 输入提问过长(最多支持 1000 字)。"

    # B. 过滤 HTML 注入 / XSS 并校验清洗后字符
    sanitized = sanitize_text(query)
    if not sanitized or not sanitized.strip():
        return False, "Input query is empty after sanitization. / 输入文本清洗后为空,请不要注入无效 HTML 代码。"

    # C. 提示词注入检测
    for pattern in _INJECTION_PATTERNS:
        if re.search(pattern, sanitized, re.IGNORECASE):
            return False, "Security Alert: Prompt injection attempt detected. Please stay on study focus. / 安全警告:检测到提示词指令注入,请专注于学术和文档阅读辅导。"

    # D. 敏感/有毒内容拦截
    for pattern in _TOXIC_PATTERNS:
        if re.search(pattern, sanitized, re.IGNORECASE):
            return False, "Safety Alert: Content violates safety guidelines. / 安全提示:提问涉及高风险或有害主题,已被系统自动拦截。"

    return True, None