Prompt 注入为何防不住?Agent 的信任边界怎么画
内容摘要:Agent 安全的核心是一句话——所有外部内容默认不可信。本章覆盖从模型输入到最终响应的完整信任边界,讲最小权限、沙箱、SQL/Shell 的安全执行,并把前面各章的安全要点收敛成一套可核查的清单。 难度:高级 | 前置知识:04 Prompt、06 工具调用、13 HITL
常见误区
只要模型足够强、系统提示足够严格,就能识别恶意内容并安全使用文件、网页、数据库和 Shell。
先给结论
Agent 安全必须假设用户输入、检索文档、MCP 描述、工具参数、工具返回和记忆内容都不可信。防线应落在最小权限、允许列表、参数化执行、沙箱、审批、脱敏和审计上。
带着这三个问题阅读:
- 从输入到最终响应,哪些位置会跨越信任边界?
- 提示注入、越权调用、数据泄露和不可信执行如何分层防御?
- 为什么 Prompt 只能参与防御,不能成为最后一道防线?
一、完整信任边界:每一处都可能是攻击入口
红色为默认不可信来源。逐条说明控制点:
| # | 边界 | 风险 | 控制 |
|---|---|---|---|
| ① | 模型输入 | 直接提示注入 | 结构隔离、最小权限、审批 |
| ② | 检索内容 | 间接注入、投毒文档 | 标注为数据、来源可信、过滤 |
| ③ | 工具描述 | 工具投毒(描述藏指令) | 只用可信工具/服务端、审查描述 |
| ④ | 工具参数 | 越权/注入参数(SQL/路径/命令) | Schema + 业务校验 + 参数化/白名单 |
| ⑤ | 工具输出 | 输出藏指令、数据泄露 | 当作数据、脱敏、大小限制 |
| ⑥ | 记忆写入 | 记忆投毒 | 写入前来源校验(10) |
| ⑦ | 外部消息 | 误发/数据外泄 | 高危→人工审批(13) |
| ⑧ | 最终响应 | 泄露系统提示/密钥/他人数据 | 输出过滤、脱敏 |
二、最小权限原则
- 读写分离:查询工具与执行工具是不同工具、不同权限。
- 查询与执行分离、预览与提交分离:见 13 的 propose/execute。
- 每个工具/子 Agent 只拿完成任务所需的最小权限(12)。
- 凭据隔离:不同工具用不同凭据,最小作用域,可轮换、可审计。
python
from dataclasses import dataclass
from typing import Literal
@dataclass(frozen=True)
class Permission:
scope: Literal["read", "write", "admin"]
resource: str # 例如 "db:mysql-test-*"
def check_permission(required: Permission, granted: set[Permission]) -> None:
"""执行前的代码级权限校验;不通过直接拒绝,不依赖 Prompt。"""
if required not in granted:
raise PermissionError(f"缺少权限:{required}")三、不要让模型拼接后直接执行
模型生成的 SQL/Shell/URL 绝不能直接拼接执行。用参数化、白名单、沙箱:
python
# 反例(禁止):SQL 注入门户
# cursor.execute(f"SELECT * FROM t WHERE id = {model_value}")
# 正例:参数化查询
def safe_query(cursor, user_id: str):
cursor.execute("SELECT * FROM orders WHERE user_id = %s", (user_id,))
# 正例:命令用白名单 + 参数数组,绝不 shell=True 拼字符串
import subprocess
ALLOWED_CMDS = {"df", "free", "uptime"}
def safe_run(cmd: str) -> str:
if cmd not in ALLOWED_CMDS:
raise ValueError(f"命令不在白名单:{cmd}")
return subprocess.run([cmd], capture_output=True, text=True, timeout=5).stdout四、沙箱:隔离不可信执行
需要执行模型生成的代码(如数据分析 Agent、编码 Agent)时,必须在沙箱中:
- 无网络或严格出网白名单、只读文件系统或临时目录、CPU/内存/时间限额、非特权用户、进程隔离(容器/子进程 + seccomp 等)。
- 沙箱逃逸是高危事件;不要用"信任模型不会写坏代码"替代沙箱。
五、提示注入的纵深防御(回顾并整合)
单一手段都不够,靠分层:
核心结论:注入无法在提示层根除;真正兜底的是"最小权限 + 校验 + 审批",让"被骗"不等于"被攻破"。
六、输出过滤:别把秘密说出去
最终响应与外发消息前做过滤:不回显系统提示词、不输出密钥/内部地址、对 PII 脱敏、限制返回其他租户数据。
python
import re
SECRET_PATTERNS = [re.compile(r"sk-[A-Za-z0-9]{8,}"), re.compile(r"(?i)password\s*[:=]\s*\S+")]
def redact(text: str) -> str:
for p in SECRET_PATTERNS:
text = p.sub("[REDACTED]", text)
return text七、失败路径
- 只靠 Prompt 防注入 → 被绕过。
- 黑名单过滤 → 总能绕过;应用白名单。
- 过度授权 → 一次注入即高危。
- 信任工具返回值 → 间接注入、投毒。
- 日志/Trace 记了密钥 → 泄露面扩大(17)。
八、测试与验证
- 注入语料库(直接+间接)红队测试,断言不越权、不泄露。
- 权限矩阵测试:无权限身份调用高危工具必须被拒。
- SQL/命令注入测试:构造恶意参数,断言被参数化/白名单挡下。
- 输出过滤测试:构造含密钥/系统提示的输出,断言被脱敏。
九、安全与权限(本章即主题)
见上。将本章清单纳入代码评审与上线检查(19)。
十、性能与成本
- 校验/过滤有开销但远低于事故成本。沙箱有资源开销,按需启用。
十一、框架差异
- 各框架提供 guardrails/中间件(如 LangChain 1.0
PIIMiddleware、OpenAI Agents SDK guardrails),但权限与业务校验仍需你实现,框架不替你判断"这个删除该不该做"。
十二、关联章节
面试复述
Agent 安全的起点是“所有外部内容默认不可信”。模型输出同样不可信,真正的安全边界由身份、权限、校验、沙箱、审批和审计构成。
复述时先给结论,再补机制、适用边界和一个可验证指标;不要只罗列框架名称或产品功能。
迁移练习
对一个具备网页读取和数据库查询能力的 Agent 画数据流图,标出每次跨信任域的位置,并为每条边配置输入校验、权限和输出过滤。
检索关键词
Agent 信任边界 提示注入 纵深防御 最小权限 参数化查询 白名单 沙箱隔离 输出脱敏
官方来源
- OWASP LLM Top 10;各框架 guardrails/安全文档;MCP 安全最佳实践(
verified_at: 2026-09-07)。
