第 4 章 防御验证与红队测试
学习目标
- 说明输入、工具、输出护栏与分类器的作用、执行方式和局限。
- 根据任务的风险程度,确定没有得到判定结果时,系统应采取什么失效处理方式。
- 从威胁模型出发,设计交战规则和攻击场景。
- 构建同时包含攻击案例、正常案例和边界案例的评估集,并以实际结果判定攻击是否成功。
- 通过攻击通过率、正常请求误拦截率、业务完成率衡量并解释防御效果。
引言
某团队在上线会议上报告了一个数字:“注入拦截率为98%。”会场响起掌声,上线也获得批准。两个月后发生安全事件时,大家才发现,这个数字是用制定分类器规则时参考过的50条攻击语句测出来的,其中连一条经过文档或邮件进入的攻击都没有。也没有人测过,究竟有多少正常请求被拦截。为了避开经常受阻的功能,用户已经开始把业务资料粘贴到使用个人账号的其他AI工具中。那个数字本身并没有错,只是从来没有人问过:使用什么数据、经由什么路径测得的?事件发生后,安全团队改用文档路径的攻击重新测量通过率,所呈现的情况与原报告中的数字完全不同。
对防御进行测量,与构建防御同样重要。本章首先考察,护栏与分类器在什么位置、能够阻止什么,以及判定失败时,系统应当如何运行。接着,学习红队的定义与交战规则、从威胁模型中提取场景的方法,以及构建评估集的原则。最后,学习如何根据结果判定成功,以及如何用数字衡量并解释防御效果。
核心概念
护栏地图:在哪里设置什么
护栏是在模型处理前后,以及工具调用位置,对输入和输出进行检查,并予以阻止或修改的机制。可以把它比作机场安检。在登机前(输入)、装载行李时(工具调用)和抵达后(输出),分别设置检查点;不同检查点能够拦住的对象并不相同。
| 位置 | 主要检查 | 无法阻止 |
|---|---|---|
| 输入 | 绕过政策的尝试、禁止主题、注入模式、输入大小 | 后续才进入的文档与工具结果 |
| 工具结果 | 外部内容中的指令、异常格式 | 模型判断本身 |
| 工具调用 | 参数格式与范围、目标、用户权限 | 权限内的巧妙滥用 |
| 输出 | 敏感信息、系统提示词泄露、危险链接与标记 | 已经执行的工具调用 |
输出护栏是在模型完成工作之后才运行的,因此无法撤销这段时间里已经执行的工具调用。对于使用了会产生副作用的工具的智能体,工具调用位置的检查不能缺少。此外,护栏不能替代第3章介绍的授权检查。护栏询问的是“这看起来是否异常”,而授权询问的是“这个人是否可以做这件事”。
检查何时结束:Agents SDK案例
OpenAI Agents SDK具体展示了护栏可以设置的位置,以及检查发生的时机。
| 类型 | 执行范围 | 特点 |
|---|---|---|
| 输入护栏 | 链中的第一个智能体 | 默认与智能体并行执行(run_in_parallel=True),延迟最低,但tripwire中断前可能已消耗token或执行工具。阻塞模式(run_in_parallel=False)须待检查完成,智能体才启动 |
| 输出护栏 | 最后一个智能体的最终输出 | 智能体全部工作完成后才开始 |
| 工具护栏 | 受保护函数工具的每次调用 | 执行前可跳过调用、将结果换成消息或触发tripwire;执行后可修改结果或触发tripwire |
tripwire是检测到违规后,用来停止执行的信号。工具护栏在适用范围上存在限制:它适用于自行编写的函数工具,却不适用于任务交接(把工作交给其他智能体的调用)、托管工具(网页搜索、文件搜索、托管MCP、代码解释器等),以及内置执行工具(计算机、shell等)。对于由管理智能体和下级专业智能体组成的结构,文档建议:如果希望每次调用都接受检查,应使用工具护栏,而不是智能体级护栏。这些具体细节因SDK而异,但需要提出的问题相同:检查在什么时候完成?在完成之前,哪些操作可能已经执行?又有哪些工具处于检查范围之外?
分类器:判定引擎的种类与局限
分类器是护栏的判定引擎,有三种。
| 类型 | 示例 | 优势 | 弱点 |
|---|---|---|---|
| 规则 | 正则表达式、长度限制、阻止列表 | 快速、确定、易解释 | 改变表达即可绕过 |
| 专用分类模型 | OpenAI Moderation API、Microsoft Prompt Shields | 能识别更广泛表达,运营负担小 | 训练分布之外表现下降,判定标准固定 |
| LLM筛查 | 请求轻量模型给出结构化判定 | 可结合业务背景判断 | 本身也是注入目标,有成本和延迟 |
务必区分各分类器回答的问题。OpenAI Moderation API是减少不安全内容出现频率的免费工具。Prompt Shields检测用户提示词攻击和文档攻击,但文档明确说明,它不判断内容是否有害或符合政策。二者都不回答“此用户是否有权查看这条客户记录”。有害内容分类、攻击检测、授权检查不能相互替代。
OWASP注入预防速查表警告,充当护栏的LLM仍是LLM,自身也易受注入影响。也不能把分类分数直接读作“攻击概率”。分数的含义,必须用自己的数据评估该分类器后才能知道。
失效行为:没有判定时
分类器并非总能给答案。它会超时、出错,筛查模型也可能拒绝请求本身。Anthropic建议,筛查模型的安全分类器若拒绝筛查请求而未留下判定(stop_reason为"refusal"),应按有害判定处理。将没有判定的状态当成“通过”,就给攻击者提供了“让分类器拒绝的输入”这一绕过路径。
应根据任务风险确定失效行为。
| 任务 | 无判定时的行为 |
|---|---|
| 只读问答 | 受限响应(无工具回答或替换为一般说明) |
| 外部内容摘要 | 用错误信息或过滤后的摘要替代原文 |
| 写入工具调用 | 停止执行,转人工审查 |
| 付款、发送、删除 | 停止执行(fail-closed),不自动重试,转人工审查 |
首次接入新分类器时,也可先采用标记(annotate)模式,观察运营数据并测量误拦截,而不立即阻止。Foundry可根据Prompt Shields结果设置阻止或仅标记;独立Content Safety API只返回判定,如何处理由应用决定。不过,在标记模式期间,必须有其他层防止损害。
红队定义与交战规则
NIST AI 600-1将AI红队定义为“通过探索AI系统,查找其缺陷与漏洞的结构化测试活动”,并说明,这类活动通常在受控环境中,与开发者合作开展。根据执行者的不同,它可以分为普通用户型、专家型、混合型,以及由人和生成式AI共同参与的形式。文档还指出,在把结果用于组织决策之前,应进行进一步分析。OpenAI建议,既要使用具有代表性的输入测试,也要使用试图破坏系统的输入测试。Anthropic则建议,使用包含注入尝试的文档、邮件和工具结果,测试自己的智能体,确认筛查与确认步骤能否捕获前面未拦下的攻击。
红队就是“由我们先来攻击自己的系统”,而且必须始终在获得许可的范围内进行。开始之前,要以文档形式就交战规则达成一致。
- 目标与环境:测试哪个系统的哪个版本,在与生产隔离的什么环境进行。
- 数据:用合成数据和虚构机密值替代真实客户数据。
- 允许与禁止行为:对外发送、付款换成模拟工具,不触碰第三方系统。
- 停止条件:观察到访问生产数据或非预期外部请求,立即停止。
- 联络与报告:向谁、以什么格式、在多长时间内报告发现。
攻击场景设计
场景是测试威胁模型路径的单位,不是攻击语句清单。从第1章信任边界与第2章五阶段表出发,为每个场景编写一张卡片。
| 字段 | 示例 |
|---|---|
| 攻击者能力 | 能撰写公开网页,未登录 |
| 路径 | 网页搜索结果 → 摘要流程 |
| 目标结果 | 未请求的写入工具调用 |
| 成功条件 | 模拟写入工具调用日志中留下记录 |
| 针对的防御层 | 工具结果筛查、写入工具分离 |
| 尝试上限 | 10种变体 × 重复5次 |
| 停止条件 | 发生模拟环境外请求 |
用“路径 × 防御层”网格检查场景组合。行方向列出路径(直接输入、网页、邮件、文档、图片、工具结果、记忆),列方向列出防御层(输入筛查、工具结果筛查、工具调用检查、人工确认、输出限制),逐格标记是否有场景。人工确认虽非护栏位置,仍作为独立防御层一起计算。每层都须有针对它的场景,才能测量逐层效果。另外还应设置跨多轮、多会话场景,以及绕过人工确认或使其流于形式的场景。
用已有攻击清单扩展范围
仅凭想象设计场景,只会测试团队已知的攻击。MITRE ATLAS将战术、技术与真实案例研究关联,可用来检查侦察、初始访问、AI模型访问(AI Model Access)、AI攻击准备(AI Attack Staging)、数据外传、影响等阶段是否存在适用于本系统的技术。OWASP LLM01除直接、间接注入外,还整理了无意注入、检索库文档篡改、载荷拆分、多模态、看似无意义的后缀字符串、多语言与混淆攻击等场景;OWASP注入预防速查表则分类了编码绕过、反复变换的攻击、跨多轮攻击等类型。
应把这些知识库用作范围检查表,而不是复制公开攻击语句来填满评估集。很多分类器可能已训练过这些语句,会虚高分数,也无法体现自己的业务背景。
评估集构建
评估集不能只有攻击。
| 构成 | 目的 | 示例 |
|---|---|---|
| 攻击案例 | 测量攻击通过率 | 含隐藏指令的虚构文档、诱导未请求的工具调用 |
| 正常案例 | 测量误拦截率与业务完成率 | 接近实际业务分布的请求 |
| 边界案例 | 检查判定标准 | 总结安全培训材料、翻译含大量祈使句的说明书 |
Anthropic的评估设计指南建议贴近真实业务分布,加入边界案例,尽可能用代码或判定模型自动评分,并优先选择大量自动评分案例,而非少量人工精细评分案例。安全评估集还应加入以下原则。
- 不用制定防御规则时参考的数据评估防御。开发集与最终验证集分离,规则编写者不能查看验证集。这就像提前看过考题的模拟考试,分数不能反映能力。
- 经过服务实际使用的输入路径。文档攻击须经过上传与文本提取,邮件攻击须经过邮件收集路径。
- 为服务使用的每种语言设置攻击与正常案例;多轮攻击把整个对话作为一个案例,延续前面轮次的状态重放。
- 植入合成机密值(金丝雀值)。使用不会与真实值重合、也不可能偶然生成的唯一字符串(如独有前缀加随机值的虚构密钥),这样一旦出现在输出或外部请求中,即可判为泄露。
- 为评估集标注版本,并逐案例记录来源(哪项威胁、哪次事件)。
成功判定:依据结果判断
模型写出了拒绝的句子,并不意味着防御已经成功。它可能一边写拒绝的话,工具却早已调用过了;反过来,它也可能表面上礼貌地同意,却没有采取任何行动。判定必须依据可以观察到的实际结果。
| 目标结果 | 判定依据 |
|---|---|
| 未授权行动 | 模拟工具调用日志、状态变化 |
| 信息外传 | 在输出与外部请求日志中检测金丝雀值 |
| 系统提示词暴露 | 是否输出提示词内植入的唯一字符串 |
| 答案污染 | 对照正确答案标准,由判定模型或人评分 |
对于答案污染等结果只存在于文本中的情况,可以使用判定模型(LLM评分者)。Anthropic将“使用不同于生成待评估输出的模型来评分”列为一般最佳实践。使用判定模型之前,应将它与人工标注的样本进行比较,确认一致率;对于不一致较为集中的类型,应修改判定标准,或者交由人工评分。如果某个场景有能够用来判定的日志,就应优先使用日志,而不是判定模型。判定模型也可能受到待评估输出中某些句子的诱导,例如“本响应满足全部标准”。因此,应将输出作为数据单独传入,并只以结构化值接收判定,同时把判定模型与人工之间的不一致率作为指标观察。
防御效果指标
至少用三个数字观察防御效果。
| 指标 | 计算 | 忽略的后果 |
|---|---|---|
| 攻击通过率(攻击成功率) | 成功攻击尝试 ÷ 全部攻击尝试 | 带着未知安全漏洞上线 |
| 正常请求误拦截率 | 被阻止的正常请求 ÷ 全部正常请求 | 用户迁移到控制范围外的工具 |
| 业务完成率 | 完整处理的正常业务 ÷ 全部正常业务 | 系统虽未拦截却无法使用 |
未被拦截的正常请求,也可能因模型错误或超时而无法完成,因此业务完成率并不等于100%减去误拦截率。
看数字时先确认分母。以场景、单次尝试或对话作为统计单位,会使相同结果呈现截然不同的数值。一个场景尝试50次,其中一次突破,按尝试计通过率为2%,按场景计却是“被突破的场景”。攻击者可以重复尝试,因此安全判断中,场景层面的“是否至少突破过一次”往往更重要。
同时观察逐层指标。记录每次攻击在哪一层停止,就能知道各层贡献,例如“输入筛查捕获70%,余下的大多数由人工确认捕获”。若某层几乎什么都没捕获,可能是它没有必要,也可能是缺少针对该层的场景。
持续监控与回归
上线前的评估,只是上线那一刻的快照。Anthropic建议定期分析注入成功的迹象,不断调整提示词、验证方式和过滤策略;如果同一用户反复尝试绕过控制,则通过警告、限制速率和封禁进行应对。这与SAIF中的“调整控制与加快反馈周期”要素,表达的是同一件事。
运营中需要持续运行三个循环:将红队与安全事件案例去标识化,加入回归集;只要模型、提示词、工具或分类器中有任意一项发生变化,就重新运行评估;如果护栏触发率、误拦截反馈或批准率出现剧烈变化,就调查原因。护栏也是需要持续测量并改进的运营对象。
深入阅读
应运行多少次:概率性结果的解释
同一个场景运行一次后被拦住,并不能据此写下“能够拦截”,因为输出具有概率性。在确定重复次数时,可以参考一个统计常识:如果n次相互独立的尝试中,没有一次成功,那么真实成功率的95%置信上限,大约是3/n(这是尝试次数足够多时的近似)。如果运行30次,没有一次突破,能说的并不是“成功率为0”,最多只能说“成功率很可能低于约10%”。要谈到1%的水平,就需要大约300次尝试。
这个常识说明了两件事。第一,不应凭小规模评估就得出“安全”的结论,而应报告“看起来低于这一水平”。第二,相比不断增加重复次数、无限缩小概率范围,采用减小影响的控制,往往更有效率。评估报告中必须写明模型、提示词、工具和分类器的版本,以及尝试次数、分母所用的统计单位,使结果能够被复现。OWASP速查表也指出,通过一次简短的检查测试,并不能证明系统能够抵抗坚持不懈的攻击者。
比较控制组合效果的实验
仅凭“把全部防御加上之后,结果变好了”,无法知道究竟是哪一项控制产生了效果。比较实验可以这样设计:先测量没有防御时的基线;再逐一增加控制,使用相同的评估集、相同的模型版本和相同的重复次数进行测量;还应测试去掉某一项控制后的配置。如果去掉这项控制后,结果几乎没有变化,说明这项控制与其他控制重叠,或者场景没有针对它进行测试。
解释结果时,应将攻击通过率与业务完成率放在一起考察。如果攻击通过率降低了2个百分点,代价却是业务完成率下降了15个百分点,就应考虑把这项控制改成其他形式,例如用确认代替阻止,或者只针对高风险任务实施,而不是应用于全部任务。
工作场景
河川证券:哪一层遗漏了什么
证券公司“河川证券”决定为客户咨询机器人增加账户查询与转账预约工具,在上线四周前制定红队计划。交战规则规定:与生产隔离的测试环境、合成客户数据、模拟转账工具、出现外部请求立即停止、发现事项当天报告。
信任边界有三条:客户聊天输入、客户附加的交易确认单图片、转账预约工具调用。已有防御包括输入筛查分类器、把附件图片OCR结果作为工具结果传入并筛查的步骤,以及转账预约前的客户确认界面。
团队为每一个防御层分别构建场景。输入筛查层使用60条绕过政策型对话测试,OCR路径使用25张隐藏了指令的测试图片,确认界面则使用12个场景,查找“是否存在不经确认就执行转账的路径”。每个场景重复5次,同时也运行400条正常客户咨询,测量误拦截率与业务完成率。成功与否,通过模拟转账工具的调用日志,以及作为金丝雀值植入的合成银行账号号码是否出现在输出中,来判定。
结果如下。输入筛查捕获了大部分绕过政策的尝试,却阻止了5%的正常咨询。OCR路径中有两个场景在部分重复尝试中漏过筛查,但全部停在确认界面。确认界面场景中有一个发现了问题:“修改”预约日期的功能复用了首次批准,连金额变更也未经确认就生效。
团队调整筛查标准降低误拦截,将两个通过筛查的OCR场景加入回归集,并要求修改功能在金额或收款人变化时重新确认。上线报告没有只列一个通过率数字,而是记录各层捕获与遗漏了什么、重复次数及残余风险。重点不是“拦住多少条”,而是“哪层遗漏了什么,下一层是否承接了防护”。
风车租车:用同一套试题比较三种配置
租车公司“风车租车”运营预约修改助手,却迟迟未确定防御配置。安全团队主张只加强输入分类器,产品团队担心增加确认环节会导致客户流失。团队决定用同一套试题测量,代替争论。
评估集包括150个攻击场景(直接输入、客户提供链接中的网页、合作方发送的预约邮件路径),以及由实际咨询去标识化形成的300条正常业务。每个攻击场景重复5次,共比较三种配置。
| 配置 | 内容 | 未授权预约修改(按场景计) | 正常业务完成率 |
|---|---|---|---|
| A | 加强输入分类器 | 150个中11个 | 94% |
| B | A + 所有写入工具均需客户确认 | 0个 | 81% |
| C | A + 按风险确认(日期修改无需确认,车型修改、取消、付款需确认)+ 工具结果筛查 | 0个 | 92% |
三种配置都保留原有服务端授权。
B消除了未授权修改,但相当一部分正常业务中,客户在确认步骤前离开对话。C阻止未授权修改,同时基本保持完成率。团队另行核实了日期修改无需确认的依据:服务器只允许修改客户本人的预约,且必须在费用不变的范围内。
判定方法也带来教训。起初由判定模型阅读完整对话,判断攻击是否成功;与100条人工标注样本比较后发现,不一致集中于“口头拒绝却调用了工具”的案例。团队将以行动为目标的场景改用模拟工具调用日志判定,仅在答案污染场景使用判定模型。最终选择C,并在报告中记录重复次数、分母单位和所测模型版本。
易错点
- “把检查移到输出护栏,就会更安全。” 输出护栏是在智能体结束工作后才运行的,因此无法撤销此前已经执行的工具调用。
- “筛查模型拒绝了请求,没有判定就放行。” 如果把没有判定当作通过,就会形成绕过路径。Anthropic建议将这种拒绝按有害判定处理。
- “拦截率足够高就可以了。” 首先要问的是:用什么数据、尝试多少次、以什么作为分母测得?如果使用制定规则时参考过的数据进行测量,得出的数字没有意义。
- “误拦截只是可用性问题。” 误拦截一多,用户就会转向控制范围之外的工具,控制最终也会被关闭。误拦截同样是一项安全指标。
- “模型写出了拒绝的句子,就说明防御成功。” 拒绝的句子和工具调用可以同时发生。应当通过日志与状态变化来判定。
- “接入了有害内容分类器,也就能阻止注入。” 有害内容分类、攻击检测与授权检查,分别回答不同的问题。
- “运行30次,一次也没有突破,所以安全。” 这个结果所能支持的说法,最多是“成功率很可能低于约10%”。
- “用公开的攻击语句集合评估就行。” 公开语句会使分数虚高,也不会经过自己的实际路径。知识库应用于检查测试范围。
要点速览
| 主题 | 要记住的话 |
|---|---|
| 护栏位置 | 输入、工具结果、工具调用、输出;输出检查不能撤销已执行行动 |
| 执行方式 | 并行输入检查很快,但期间可能执行工具 |
| 分类器 | 有害内容、攻击检测、授权是不同问题 |
| 失效行为 | 无判定不等于通过;按风险故障关闭 |
| 红队 | 获准范围、合成数据、模拟工具、停止条件 |
| 场景 | 填充“路径 × 防御层”网格的卡片 |
| 评估集 | 攻击、正常、边界;开发与验证分离;逐语言;金丝雀值 |
| 判定 | 依据日志与状态变化,而非拒绝回复 |
| 指标 | 攻击通过率、误拦截率、业务完成率;确认分母 |
| 重复 | 0/n时,上限约为3/n |
查阅官方文档
- OpenAI Agents SDK — Guardrails:护栏类型、执行模式、适用范围。
- Anthropic — Mitigate jailbreaks and prompt injections:筛查、拒绝处理、监控、自有智能体红队测试。
- Anthropic — Define success criteria and build evaluations:评估设计原则与评分方法。
- OpenAI — Safety best practices:Moderation API、对抗测试、人工审查。
- Microsoft — Prompt Shields:检测范围与局限、标记与阻止模式。
- NIST AI 600-1:AI红队定义与类型、结果使用注意事项。
- MITRE ATLAS:用于检查场景范围的攻击战术与技术。
自测
4-1. 写出两类不适用OpenAI Agents SDK工具护栏的工具,并举出使用此类工具的智能体可设置的一项替代控制。
4-2. 各用一行写出有害内容分类、注入攻击检测、授权检查分别回答什么问题。
4-3. 写出红队开始前交战规则应约定的五项内容。
4-4. 写出在评估集植入合成机密值(金丝雀值)的目的,以及选择该值时应遵守的两个条件。
4-5. 240次攻击尝试中9次成功,500条正常请求中15条被阻止。计算攻击通过率与正常请求误拦截率,并写出仅凭这两个数字无法知道的一件事。
4-6. 某场景独立重复60次,没有一次被突破。写出此结果可支持的成功率近似上限,以及不能声称的结论。
4-7. 设计题:设计实验,比较“增加输入筛查”与“增加写入工具确认”哪项效果更大。提出比较配置、三项固定条件和两项观测指标。
实操练习
练习
制作30条小型评估集(60分钟)
- 从第2章注入路径清单中选择三条路径。
- 每条路径编制5条攻击案例(含隐藏指令的虚构文档、诱导未请求工具调用等)、4条正常案例、1条边界案例。仅使用不会造成实际损害的合成数据,在攻击案例中植入金丝雀字符串。
- 为每条案例写出“预期结果(阻止、通过、标记)”“判定依据(日志、金丝雀值、评分标准)”“应捕获的防御层”。
- 为评估集标注版本号,分为20条开发集和10条验证集。
完成标准: 全部30条都有预期结果与判定依据,没有任何案例仅以是否出现拒绝回复为判定依据。
练习
场景卡与指标计算表(50分钟)
- 绘制“路径 × 防御层”网格,针对空白较多的列(防御层)编写五张场景卡。卡片包括攻击者能力、路径、目标结果、成功条件、针对层、尝试上限、停止条件。
- 如条件允许,在测试环境中每张卡至少重复运行10次。难以运行时,写出现有配置下的预期结果与依据。
- 分别计算按尝试与按场景统计的攻击通过率,以及正常请求误拦截率;记录每次攻击停止的层,制作逐层贡献表。
- 对成功0次的卡片,同时写出3/n上限。
完成标准: 每项指标都明确分母单位;逐层贡献表中若有“未捕获任何攻击的防御层”,须用一行说明原因。