为什么你需要一份安全检查清单

智能体产品的上线安全审查,与传统软件有本质区别。传统软件的安全边界由代码和接口定义,而智能体的安全边界还要面对自然语言这个"无限输入空间"。一个精心构造的提示词可以让智能体泄露系统指令、执行未授权操作、甚至越权访问数据。

2024 年以来,我们已经看到太多智能体安全事故:ChatGPT 的 prompt injection 导致系统提示词泄露、Bing Chat 的"人格分裂"事件、各类 Agent 框架的 RCE 漏洞。这些事故的共同点是——它们不是传统意义上的代码漏洞,而是架构层面的安全设计缺失

以下是我整理的 20 项必做安全检查,覆盖从输入到输出的全链路。建议在每次版本上线前逐项核对。

输入安全(1-5)

1. 提示注入防护

检查项:是否对用户输入进行了提示注入检测和过滤?

提示注入(Prompt Injection)是智能体面临的首要安全威胁。攻击者通过在用户输入中嵌入恶意指令,试图覆盖系统提示词或改变智能体行为。

防护措施

import re

class PromptInjectionGuard:
    # 常见的提示注入模式
    INJECTION_PATTERNS = [
        r"ignore\s+(all\s+)?previous\s+instructions",
        r"disregard\s+(the\s+)?above",
        r"you\s+are\s+now\s+a\s+",
        r"system\s*:\s*",
        r"<\|im_start\|>",
        r"\[SYSTEM\]",
        r"reveal\s+your\s+(system\s+)?prompt",
        r"repeat\s+everything\s+above",
    ]
    
    def check(self, user_input: str) -> tuple[bool, str]:
        for pattern in self.INJECTION_PATTERNS:
            if re.search(pattern, user_input, re.IGNORECASE):
                return False, f"检测到可能的提示注入: {pattern}"
        return True, "通过"
    
    def sanitize(self, user_input: str) -> str:
        """对用户输入进行安全处理"""
        # 1. 移除特殊标记
        sanitized = re.sub(r'<\|[^|]+\|>', '', user_input)
        # 2. 限制长度
        if len(user_input) > 10000:
            sanitized = sanitized[:10000]
        # 3. 转义可能的指令标记
        sanitized = sanitized.replace("SYSTEM:", "SYSTEM-")
        return sanitized

2. 输入长度与复杂度限制

检查项:是否对输入长度、嵌套层级和复杂度设置了上限?

超长输入不仅消耗 Token 预算,还可能用于"上下文淹没"攻击——用大量文本淹没系统提示词。

INPUT_LIMITS = {
    "max_length": 5000,          # 最大字符数
    "max_lines": 100,             # 最大行数
    "max_nested_depth": 3,        # JSON/嵌套结构最大深度
    "max_urls": 10,               # 最大URL数量
    "max_base64_size": 1024 * 100 # Base64 最大100KB
}

3. 敏感信息检测

检查项:是否对用户输入中的敏感信息进行了检测和脱敏?

用户可能在对话中无意输入密码、密钥、身份证号等敏感信息。智能体应主动检测并提醒。

SENSITIVE_PATTERNS = {
    "api_key": r"sk-[a-zA-Z0-9]{32,}",
    "aws_key": r"AKIA[0-9A-Z]{16}",
    "id_card": r"\d{17}[\dXx]",
    "phone": r"1[3-9]\d{9}",
    "email": r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}",
}

4. 多模态输入安全

检查项:如果支持图片/文件上传,是否对多模态输入进行了安全检查?

图片中可以嵌入文本(如截图中的提示注入),上传文件可能包含恶意内容。

  • 图片 OCR 后进行提示注入检测
  • 文件大小和类型白名单校验
  • 文件内容扫描(特别是代码文件)
  • EXIF 信息剥离

5. 编码与混淆检测

检查项:是否检测了 Base64、Unicode、HTML 实体等编码绕过?

攻击者经常使用编码绕过输入过滤:

def detect_encoding_bypass(text: str) -> list[str]:
    threats = []
    # Base64 检测
    if re.search(r'[A-Za-z0-9+/=]{50,}', text):
        threats.append("疑似Base64编码内容")
    # Unicode 转义
    if re.search(r'\\u[0-9a-fA-F]{4}', text):
        threats.append("疑似Unicode转义")
    # HTML 实体
    if re.search(r'&#\d+;|&#[xX][0-9a-fA-F]+;', text):
        threats.append("疑似HTML实体编码")
    return threats

权限与执行安全(6-10)

6. 工具调用权限控制

检查项:每个工具调用是否有明确的权限校验?

智能体的工具调用是最危险的攻击面。必须实现最小权限原则:

from enum import Enum
from dataclasses import dataclass

class ToolPermission(Enum):
    READ_ONLY = "read_only"      # 只读操作
    WRITE_LOCAL = "write_local"  # 本地写入
    WRITE_REMOTE = "write_remote" # 远程写入
    EXECUTE = "execute"          # 代码执行
    NETWORK = "network"          # 网络请求

@dataclass
class ToolConfig:
    name: str
    permission: ToolPermission
    requires_approval: bool
    rate_limit: int  # 每分钟最大调用次数
    allowed_in_sandbox: bool = True

TOOL_CONFIGS = {
    "web_search": ToolConfig("web_search", ToolPermission.NETWORK, False, 30),
    "file_read": ToolConfig("file_read", ToolPermission.READ_ONLY, False, 100),
    "file_write": ToolConfig("file_write", ToolPermission.WRITE_LOCAL, True, 10),
    "code_execute": ToolConfig("code_execute", ToolPermission.EXECUTE, True, 5),
    "send_email": ToolConfig("send_email", ToolPermission.WRITE_REMOTE, True, 3),
}

7. 沙箱隔离

检查项:代码执行和文件操作是否在沙箱环境中进行?

任何涉及代码执行的工具调用都应在隔离环境中运行:

  • Docker 容器隔离(CPU、内存、网络限制)
  • 文件系统只读挂载
  • 网络访问白名单
  • 执行超时限制(建议 30 秒)
  • 输出大小限制

8. 速率限制与配额

检查项:是否对工具调用和 API 请求设置了速率限制?

from collections import defaultdict
import time

class RateLimiter:
    def __init__(self):
        self.calls = defaultdict(list)
    
    def check(self, user_id: str, tool_name: str, 
              limit: int, window: int = 60) -> bool:
        now = time.time()
        key = f"{user_id}:{tool_name}"
        # 清理过期记录
        self.calls[key] = [
            t for t in self.calls[key] if now - t < window
        ]
        if len(self.calls[key]) >= limit:
            return False
        self.calls[key].append(now)
        return True

9. 人在回路(Human-in-the-Loop)

检查项:高风险操作是否需要人工确认?

以下操作必须强制人工确认:

  • 发送邮件/消息给外部用户
  • 修改或删除持久化数据
  • 执行涉及金钱交易的 API
  • 访问其他用户的私人数据
  • 修改系统配置

10. 权限提升检测

检查项:是否检测和阻止权限提升尝试?

智能体不应在运行时请求超出预设范围的权限。任何"请给我管理员权限"或"请执行 sudo“的请求都应被拒绝并记录。

输出安全(11-14)

11. 输出内容过滤

检查项:是否对智能体的输出进行了内容安全过滤?

class OutputFilter:
    def __init__(self):
        self.content_filters = [
            self._check_pii,        # 个人信息泄露
            self._check_secrets,    # 密钥泄露
            self._check_harmful,    # 有害内容
            self._check_copyright,  # 版权内容
        ]
    
    def filter(self, output: str, context: dict) -> tuple[bool, str]:
        for f in self.content_filters:
            passed, reason = f(output, context)
            if not passed:
                return False, reason
        return True, "通过"
    
    def _check_secrets(self, output, context):
        # 检查输出中是否包含 API 密钥等
        if re.search(r'sk-[a-zA-Z0-9]{32,}', output):
            return False, "输出中检测到API密钥"
        return True, ""

12. 系统提示词泄露防护

检查项:是否防止系统提示词通过输出泄露?

用户可能通过特殊提问诱导智能体输出系统提示词。防护措施:

  • 在系统提示词中加入明确的保密指令
  • 对输出进行后处理,检测是否包含系统提示词片段
  • 使用单独的过滤层检查输出与系统提示词的相似度

13. 幻觉与事实性检查

检查项:是否对关键事实性输出进行了验证?

对于涉及具体数据、日期、引用的输出,应建立事实验证机制:

  • 关键数据与知识库交叉验证
  • 引用来源验证
  • 置信度阈值过滤
  • 不确定时标注"请核实”

14. 输出格式注入防护

检查项:是否防止输出中包含恶意 Markdown/HTML/JavaScript?

如果智能体输出渲染为 HTML,需要防范 XSS:

import html

def sanitize_output(output: str) -> str:
    # 转义 HTML 特殊字符
    output = html.escape(output)
    # 移除可能的 script 标签
    output = re.sub(r'(?i)<script[^>]*>.*?</script>', '', output, flags=re.DOTALL)
    # 移除事件处理器
    output = re.sub(r'(?i)on\w+\s*=\s*["\'][^"\']*["\']', '', output)
    return output

数据与隐私安全(15-17)

15. 数据最小化原则

检查项:智能体是否仅收集和传输必要的数据?

  • 对话日志只记录必要字段,不记录完整上下文
  • 传给第三方 API 的数据先进行脱敏
  • 用户画像数据按需加载,不全量传入上下文

16. 数据存储加密

检查项:存储的对话历史和用户数据是否加密?

  • 对话记录 AES-256 加密存储
  • 数据库连接使用 TLS
  • Redis 开启 AUTH 和 TLS
  • 备份数据加密
  • 密钥轮换机制

17. 合规性审查

检查项:是否满足目标市场的法规要求?

  • 中国大陆:生成式 AI 服务备案、算法推荐备案、数据出境安全评估
  • 欧盟:GDPR 合规、AI Act 风险分类
  • 美国:COPPA(如涉及未成年人)、各州 AI 法规
  • 数据保留策略:默认 30 天自动删除

监控与响应(18-20)

18. 异常行为监控

检查项:是否建立了实时异常行为检测机制?

@dataclass
class AnomalyAlert:
    type: str
    severity: str  # info, warning, critical
    user_id: str
    description: str
    timestamp: str

# 监控指标
MONITORING_RULES = {
    "rapid_tool_calls": {
        "condition": "同一用户1分钟内工具调用>20次",
        "severity": "warning"
    },
    "repeated_injection": {
        "condition": "同一用户10分钟内触发注入检测>3次",
        "severity": "critical"
    },
    "unusual_output_length": {
        "condition": "单次输出超过5000字符",
        "severity": "info"
    },
    "off_topic_tools": {
        "condition": "工具调用与用户问题主题不相关",
        "severity": "warning"
    }
}

19. 审计日志

检查项:是否记录了完整的审计日志,可供事后追溯?

审计日志应包含:

  • 所有用户输入和智能体输出的完整记录
  • 所有工具调用的参数和返回值
  • 权限校验和人工审批记录
  • 系统提示词版本和模型版本
  • 异常和告警事件

日志保留策略:在线 30 天,归档 90 天,合规要求的按法规保留。

20. 应急响应预案

检查项:是否有智能体安全事件的应急响应预案?

预案应包含以下步骤:

  1. 一键熔断:紧急停止所有智能体服务,切换到降级模式
  2. 会话隔离:冻结可疑会话,阻止进一步交互
  3. 影响评估:快速确定受影响的用户和数据范围
  4. 证据保全:保留完整日志和会话记录
  5. 用户通知:按法规要求通知受影响用户
  6. 事后复盘:分析根因,更新安全策略

检查清单使用指南

建议按以下方式使用这份检查清单:

上线前:逐项检查,每项都需要明确的责任人和验证方式。不通过的项目要么修复,要么记录为已知风险并获得审批。

运行中:定期(建议每月)重新检查,特别是第 1、6、11、18 项。

事件后:安全事件发生后,用清单进行差距分析,找出哪些检查项失效了。

安全不是一次性工程,而是持续的过程。这份清单会随着威胁态势的演变而更新。保持警惕,保持更新。

加入讨论

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

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