TT Lab
博客 开始
学习 学习路径 课程

LLM 应用安全——从注入到输出处理

数据变成指令的那一刻——直接与间接提示注入

在 TT Lab 中继续学习

一句话总结

模型无法确切区分输入中哪段文字是命令、哪段是资料。所以“可以做什么”必须由模型之外的服务器策略来决定,而不是由模型决定。

为什么需要它

想一想 SQL 注入就容易理解了。代码和数据混在一个字符串中,数据就被当作代码执行了,于是我们用占位符(参数化)在两者之间建立了一条由引擎守护的边界。LLM 没有这样的边界。系统文本、用户问题、检索到的文档、工具结果,最终都是拼接成一行的词元序列,而“从这里开始是资料”的标记,只是模型通过训练习得的倾向,并不是强制执行的规则。

用户在自己的问题中夹带指令,这是直接注入。更棘手的是间接注入。如果应用检索来的文档、要求总结的网页或邮件、工具返回的结果中藏着看起来像指令的句子,攻击者根本不需要与我们的用户对话,只要埋下一份文档就行。接入了 RAG 和工具的应用,这条路就越宽。OWASP LLM Top 10 2025 把它列为第一号风险(LLM01 提示注入)。

它如何工作

这门课程的实验不用外部模型,而是使用按规则运行的假模型。只有相同输入总给出相同回答,评分器才能反复以同样的结果测量“发出攻击后发生了什么”。这个模型是把真实模型的弱点放大后的漫画版。

假模型的性质 在真实模型中对应的情况
无论指令标记出现在输入的哪里都会照做 角色区分只是习得的倾向,所以有时会照做资料中的指令
把全角、空格、大小写、base64 都读作同一条指令 改写的指令、其他语言、编码过的指令也能听懂
以文本行的形式给出工具调用 函数调用最终也是由应用来解释的输出

坦白说,有两点局限。真实模型是概率性的。同一个攻击可能十次中成功一次,换个说法也可能成功。在假模型面前“过滤标记的过滤器”奏效,只说明过滤器摸清了这个模型的语法,并不能证明同样的过滤器在真实模型面前也能挡住。这就是通过几次测试并不能证明安全的原因。

所以防御的重心要放在模型之外。

为什么这些层必须在模型“之外”,想想失败时就明白了。过滤器一漏,模型就会照做指令,这时最后剩下的就是服务器的规则。反过来,服务器规则出现漏洞是代码缺陷,能通过测试找到,修好一次就不会再漏。在概率性的部件前面放上确定性的部件——这就是贯穿整门课程的原则。

间接注入的入口比想象的多。不只是检索文档,用户粘贴的邮件、从以往对话中保存的笔记、读取网页的工具结果,甚至其他智能体转交的摘要,全都会成为模型输入。可以这样看:每给应用接上一个“记忆”或“工具”,别人写的文字进来的门就多了一扇。

现场遇到的情形

典型的事故有:总结客户上传文档的内部助手按文档中的句子发出了邮件;网页摘要工具按页面中的指令把对话内容发到了外部地址。从日志看,形态总是一样的:某个请求的提示中混入了来自外部的文字,而恰恰在那个请求中发生了没人吩咐的行为。所以在运维中,记录下提示中从哪里放入了什么(请求 id、片段、出处),就成了调查的出发点。

调查总是从副作用倒推上去。从发出去的一封邮件追到请求 id,从请求 id 追到该请求的输入片段,再从片段追到那段文字的出处(文档、笔记、问题、配置)。如果记录中没有片段和出处,这条链就会断开,停在“模型表现异常”上。所以提示记录不应设计成调试用的转储,而应设计成审计资料——正如下一个模块所见,要在遮蔽敏感信息的前提下。

但这并不是说要抛弃过滤器和分隔标记。用“以下是资料”之类的标记把外部文字包起来,并把看起来像指令的句子标出来,真实模型照做的概率通常会下降。只不过,下降和被挡住是两回事。辅助层用于检测和告警,而行为的许可永远由服务器的规则来给。

接下来的实验要做什么

展开一个内部文档助手,从记录中读出模型实际收到的输入,在一堆文档中找出所有形态不同的隐藏指令,并复现一次攻击。然后依次加入收件人规则、搁置与确认、由服务器附加的出处,最后分辨三个部门中同一症状(发到公司外部的邮件)经由不同路径发生的故障事件。