第2章 输入侧防御:提示词注入的检测与过滤 在第 1 章里,我们把敌人看清楚了:大模型应用之所以"天生脆弱",根本原因在于模型无法从结构上区分"你给我的指令"和"你给我的数据"。攻击者也正是利用这一点,把恶意指令伪装成一段普通文本,混进上下文,让模型乖乖照做。 从这一章开始,我们转入攻防的下半场——怎么防。先说一个重要的认知:防御从来不是一句"请模型保持安全"就能解决的事。它是一条需要层层设防的流水线,每一层都只解决一部分问题,叠加起来才形成真正的护栏。本章聚焦"输入侧",也就是在用户或外部系统的内容真正进入模型上下文之前,我们能做的所有事。 输入侧到底在防谁 要把防御做对,先得把威胁模型想清楚。输入侧要防的有三类来源,它们的共同点是:都可能在你毫无察觉时,把"指令"混进"数据"里。
在第 1 章里,我们把敌人看清楚了:大模型应用之所以"天生脆弱",根本原因在于模型无法从结构上区分"你给我的指令"和"你给我的数据"。攻击者也正是利用这一点,把恶意指令伪装成一段普通文本,混进上下文,让模型乖乖照做。
从这一章开始,我们转入攻防的下半场——怎么防。先说一个重要的认知:防御从来不是一句"请模型保持安全"就能解决的事。它是一条需要层层设防的流水线,每一层都只解决一部分问题,叠加起来才形成真正的护栏。本章聚焦"输入侧",也就是在用户或外部系统的内容真正进入模型上下文之前,我们能做的所有事。
要把防御做对,先得把威胁模型想清楚。输入侧要防的有三类来源,它们的共同点是:都可能在你毫无察觉时,把"指令"混进"数据"里。
第一类是终端用户输入。就是聊天框里那个真实的人。他可能是好奇的开发者,也可能是有组织的红队,甚至只是无意间粘贴了一段从别处复制来的文本,而那段文本里恰好藏着"忽略以上指令"的字样。
第二类是外部检索或工具返回的内容。这是最容易被忽略、也最危险的来源。当你的应用接入了 RAG(检索增强生成)、调用了外部 API、或者抓取了网页,这些返回内容本质上是"不可信的外部数据",却会被直接拼进提示词。攻击者不需要接触你的聊天框,只要想办法让一段恶意指令出现在你检索到的某篇文档、某个网页、某条 API 响应里,就能完成"间接注入"(indirect prompt injection)。
第三类是多模态输入里藏的文本。一张图片里的字、一份 PDF 里被刻意排版的段落、一段语音转写后的文字,都可能携带指令。模型"看"到的不是像素,而是被解析后的文本,攻击者可以利用这一点藏东西。
针对输入侧,我主张把防御拆成三道清晰、可落地的防线,它们分别对应本章的三节:
下图把"一段输入在进模型之前的旅程"画出来,你可以把它当成本章的总纲:
注意这条链路的顺序:清洗和隔离在最前面,检测在中间,拦截决策在最后。为什么不让检测打头阵?因为检测永远有漏报,而清洗和隔离能直接砍掉一大类攻击的"作案工具"——比如把用户文本统一包进代码块、剥掉控制字符,很多最朴素的注入就直接失效了,根本到不了检测环节。
很多团队一上来就训练分类器、接越狱检测 API,投入不小,效果却一般。我见过最典型的一种失败是:系统提示词写得洋洋洒洒,却把所有用户内容直接拼接在后面,没有任何分隔,也没有任何"这是数据不是指令"的声明。结果攻击者只要一句"忽略以上全部指令"就能让护栏形同虚设——因为模型眼里的上下文根本没有"指令区"和"数据区"的边界。
所以请记住本章的第一性结论:边界隔离是输入侧防御的地基,没做隔离就上检测,等于在沙地上盖楼。 2.1 我们会把这件事讲透,2.2、2.3 再往上叠。阅读顺序不要跳。
有人会问:大模型不是都做了安全对齐(RLHF、安全微调)吗?为什么不能靠它挡注入?答案是:对齐确实能挡住大量明显恶意请求,但它和"输入侧防御"是两件事。对齐面对的是"用户直接说坏话",而注入是"把坏话藏成好数据"——对齐模型往往对"看起来像正常数据"的内容放松警惕。更麻烦的是,过度依赖对齐会带来误伤:为了防注入把正常的用户指令也拦了(过度拒绝,over-refusal),反而伤害体验。所以输入侧必须靠结构化的工程手段兜底,对齐只是最后一道软防线,不能当主力。
为了让你一眼看清风险分布,把三类来源放一起对比:
| 来源 | 是否经聊天框 | 攻击者可控度 | 防御重点 |
|---|---|---|---|
| 终端用户输入 | 是 | 高 | 围栏+清洗+检测 |
| 外部检索/工具返回 | 否 | 中高(污染源) | 同为数据、等同隔离 |
| 多模态藏文 | 视通道 | 中 | 解析后当文本处理 |
记住最后一行那句话的引申义:凡是会进入上下文的字节,哪怕它来自"内部系统",只要它可能被外部污染,就该按不可信数据处理。这是很多架构师漏掉的一课。
防御资源有限,顺序很重要。把隔离和清洗做扎实,往往能用最少的人力拦掉最多、最朴素的攻击——这类攻击占线上真实流量的大头。等隔离把水位降下来,再去上检测引擎和分类器,要兜的尾巴就短得多,模型也更容易训练、误报率更低。反过来,跳过隔离直接堆检测,相当于让分类器去识别"伪装成数据的指令",而数据区本身又没隔离,分类器既要分辨语义又要分辨边界,任务难度翻倍,效果自然打折扣。所以这一章的顺序不是随意排的:先地基,后楼体。
读完这一章,你应该能独立画出一张"输入防御流水线图",并回答三个问题:我的应用里,哪些输入属于不可信外部数据?我有没有在结构上把指令和数据分开?当清洗和隔离都挡不住时,我的检测引擎能不能兜住最后一棒?带着这三个问题去读 2.1,你会比直接背方案收获大得多。
下一节(2.1)我们就从地基挖起:边界隔离与输入清洗。把围栏、最小权限、格式漂白、工具闸门这四件事做对,你 already 挡住了线上绝大多数朴素攻击。