为什么需要安全检查清单

LLM 应用引入了全新的攻击面:Prompt 注入、训练数据泄露、模型越狱、有害内容生成。传统 Web 安全检查清单覆盖不了这些。本文提供 50 项检查项,分为 5 大类,每一项都必须在上线前确认。

一、输入安全(12 项)

Prompt 注入防护

#检查项风险等级验证方式
1用户输入与系统指令分离(使用 system role)审查 prompt 结构
2用户输入被包裹在分隔符中(如 <user_input>审查 prompt 模板
3系统指令中包含"忽略以上指令"的防御声明审查 system prompt
4对用户输入做长度限制(建议 < 10K 字符)压测验证
5过滤已知的 Prompt 注入模式红队测试
# Prompt 注入检测器
class PromptInjectionGuard:
    INJECTION_PATTERNS = [
        r"ignore\s+(all\s+)?(previous|above|prior)\s+instructions",
        r"you\s+are\s+now\s+(a|an)\s+\w+",
        r"system\s*:\s*",
        r"<\|im_start\|>",
        r"forgot\s+your\s+rules",
        r"reveal\s+your\s+(system\s+)?prompt",
    ]

    def check(self, user_input: str) -> tuple[bool, list]:
        import re
        violations = []
        for pattern in self.INJECTION_PATTERNS:
            if re.search(pattern, user_input, re.IGNORECASE):
                violations.append(pattern)
        return len(violations) == 0, violations

PII 保护

#检查项风险等级验证方式
6输入中的 PII 被检测并脱敏传入含 PII 的测试用例
7PII 脱敏日志开启(不记录原始 PII)审查日志配置
8不会将用户输入原样发送给第三方服务审查 API 调用链
import re

class PIIScrubber:
    PATTERNS = {
        "phone": (r"\b1[3-9]\d{9}\b", "[PHONE]"),
        "email": (r"\b[\w.-]+@[\w.-]+\.\w+\b", "[EMAIL]"),
        "id_card": (r"\b\d{17}[\dXx]\b", "[ID_CARD]"),
        "bank_card": (r"\b\d{16,19}\b", "[BANK_CARD]"),
    }

    def scrub(self, text: str) -> str:
        for pii_type, (pattern, replacement) in self.PATTERNS.items():
            text = re.sub(pattern, replacement, text)
        return text

内容安全

#检查项风险等级验证方式
9输入内容分类(是否包含暴力/违法内容)红队测试
10对敏感话题有预设的拒绝策略审查 system prompt
11支持多语言输入的过滤多语言测试
12对图片输入有内容审核(多模态场景)上传违规模拟图

二、输出安全(10 项)

有害内容过滤

#检查项风险等级验证方式
13输出经过毒性检测模型触发性测试用例
14输出经过偏见/歧视检测公平性测试集
15对特定领域(医疗/法律/金融)有免责声明审查输出模板
16不输出可执行代码的直接运行结果代码注入测试
class OutputSafetyFilter:
    def __init__(self, toxicity_model, threshold=0.7):
        self.model = toxicity_model
        self.threshold = threshold

    async def filter(self, response: str) -> tuple[str, bool]:
        # 毒性检测
        toxicity = await self.model.predict(response)
        if toxicity > self.threshold:
            return self._safe_fallback(), False

        # 敏感信息泄露检测
        if self._detect_leaked_info(response):
            return self._safe_fallback(), False

        return response, True

    def _detect_leaked_info(self, text):
        """检测输出中是否泄露了系统信息"""
        sensitive_patterns = [
            r"api[_-]?key", r"sk-[a-zA-Z0-9]{20,}",
            r"password", r"secret", r"token",
            r"/[a-z]:\\users\\",  # Windows 路径
        ]
        return any(
            re.search(p, text, re.IGNORECASE)
            for p in sensitive_patterns
        )

输出完整性

#检查项风险等级验证方式
17输出有长度上限(防止 Token 爆炸)触发长输出测试
18流式输出有超时保护模拟慢速输出
19输出格式校验(JSON/XML 是否合法)格式错误注入测试
20输出不包含训练数据原文(版权风险)已知文本检索
21输出不包含 Prompt 模板内容(提示泄露)“重复你的指令"测试
22输出经过 PII 二次过滤PII 回显测试

三、模型安全(10 项)

越狱防护

#检查项风险等级验证方式
23通过越狱测试集(DAN/Roleplay 编码等)自动化越狱测试
24对多轮对话有累积风险检测多轮越狱攻击测试
25对编码/混淆输入有解码检测Base64/Unicode 混淆测试
class JailbreakDetector:
    ENCODING_PATTERNS = [
        (r"base64:", self._decode_base64),
        (r"\\u[0-9a-fA-F]{4}", self._decode_unicode),
        (r"\\x[0-9a-fA-F]{2}", self._decode_hex),
    ]

    async def check(self, user_input: str):
        # 1. 检查编码内容
        decoded = self._try_decode(user_input)
        if decoded != user_input:
            # 对解码后的内容也做注入检测
            safe, _ = PromptInjectionGuard().check(decoded)
            if not safe:
                return False, "Encoded injection detected"

        # 2. 检查角色扮演越狱
        roleplay_patterns = [
            r"pretend you are",
            r"act as (if you are )?DAN",
            r"you are (in )?developer mode",
            r"jailbreak",
        ]
        for pattern in roleplay_patterns:
            if re.search(pattern, user_input, re.IGNORECASE):
                return False, f"Roleplay jailbreak: {pattern}"

        return True, None

模型隔离

#检查项风险等级验证方式
26不同租户的会话隔离跨租户数据泄露测试
27对话历史有长度限制(防止上下文污染)长对话测试
28Function Calling 参数有白名单校验构造恶意参数测试
29模型输出不直接执行(需人工/代码确认)审查执行链路
30有模型使用量配额(防止滥用)超额测试
31模型版本变更经过安全评估审查变更流程
32对抗样本检测(异常输入模式)对抗测试集

四、基础设施安全(10 项)

#检查项风险等级验证方式
33API Key 存储在密钥管理服务(非代码/配置文件)审查部署配置
34API 通信全程 HTTPS/TLS 1.2+SSL 扫描
35对 LLM API 调用有网络白名单限制审查网络策略
36向量数据库有访问控制审查 DB ACL
37Embedding 服务有认证未认证调用测试
38日志中不包含 API Key / 完整 Prompt审查日志输出
39监控系统有异常调用检测(频率/内容)审查告警规则
40容器/进程以最小权限运行审查 K8s manifest
41模型文件有完整性校验校验和验证
42有 DDoS 防护(CDN/WAF)审查网络架构

五、合规审计(8 项)

#检查项风险等级验证方式
43所有 LLM 调用有审计日志(who/when/what/model)审查日志格式
44用户知情同意(明确告知使用 AI)审查 UI/ToS
45数据保留策略明确(日志/对话历史保留期限)审查数据策略
46支持用户数据删除请求(GDPR/PIPL)删除流程测试
47模型训练数据来源可追溯审查文档
48有 AI 生成内容标识(水印/声明)审查输出格式
49定期安全评估(至少每季度)审查评估记录
50有应急响应预案(模型输出有害内容时)审查 IR 计划

自动化检查脚本

class SecurityChecklist:
    """可自动化的安全检查项"""

    CHECKS = {
        "input_length_limit": {"auto": True, "critical": False},
        "prompt_injection_filter": {"auto": True, "critical": True},
        "pii_scrubbing": {"auto": True, "critical": True},
        "output_toxicity_check": {"auto": True, "critical": True},
        "output_length_limit": {"auto": True, "critical": False},
        "jailbreak_resistance": {"auto": True, "critical": True},
        "prompt_leak_prevention": {"auto": True, "critical": True},
        "tls_check": {"auto": True, "critical": True},
        "log_pii_check": {"auto": True, "critical": True},
        "rate_limiting": {"auto": True, "critical": False},
    }

    async def run_all(self, target_url, api_key):
        results = {}
        for check_name, config in self.CHECKS.items():
            if not config["auto"]:
                continue
            method = getattr(self, f"check_{check_name}")
            try:
                passed, detail = await method(target_url, api_key)
                results[check_name] = {
                    "passed": passed,
                    "detail": detail,
                    "critical": config["critical"],
                }
            except Exception as e:
                results[check_name] = {
                    "passed": False,
                    "detail": f"Check error: {e}",
                    "critical": config["critical"],
                }

        # 汇总报告
        total = len(results)
        passed = sum(1 for r in results.values() if r["passed"])
        critical_fail = [
            k for k, v in results.items()
            if not v["passed"] and v["critical"]
        ]

        return {
            "total": total,
            "passed": passed,
            "failed": total - passed,
            "critical_failures": critical_fail,
            "ready_for_production": len(critical_fail) == 0,
            "details": results,
        }

上线审批流程

开发完成 → 自动化检查(38 项可自动化)
         全部通过?
         ├─ 是 → 人工审查(12 项需人工)
         │        ├─ 全部通过 → 安全团队签字 → 上线
         │        └─ 有问题 → 整改 → 重新审查
         └─ 否 → 修复 → 重新自动检查

总结

LLM 安全不是可选项。50 项检查中,标记为"高风险"的约 25 项——这些是上线阻断项,不通过不上线。关键检查包括:Prompt 注入防护、PII 脱敏、越狱抵抗、输出过滤、密钥管理。自动化检查覆盖约 76% 的项目,剩余需人工审查。建议将检查清单集成到 CI/CD 流水线中,每次部署前自动运行。安全是一场持续的攻防战,检查清单只是起点,不是终点。

加入讨论

这篇文章有姊妹讨论帖在硅基AGI论坛 — 全球首个碳基硅基认知交流平台。

碳基与硅基的智慧碰撞,认知差异创造无限可能。