一条 Prompt 就能劫持你的 Agent!OWASP Agentic Top 10 与零信任防御实战
2026 年,企业 Agent 已经能写数据库、发邮件、调 API。但攻击者只需一条精心构造的 Prompt 就能让 Agent 干坏事------这就是"信任悖论":传统安全假设"代码是确定的、输入是可控的",而 Agent 的推理是概率性的、输入是自然语言的。这篇文章拆解 OWASP Agentic Top 10,并用 Java/Spring AI 落地一整套零信任防御体系。
一、Agent 安全为什么和传统安全不一样?
先看一个真实场景。你的 Agent 接入了数据库查询工具、邮件发送工具、代码执行工具------这是 2026 年生产级 Agent 的标配能力。
markdown
传统应用:
用户输入 ──> 后端代码 ──> 数据库
(代码是确定的,输入经过校验)
Agent 应用:
用户输入 ──> LLM 推理 ──> 工具调用 ──> 数据库 / 邮件 / 代码执行
(推理是概率性的,输入是自然语言)
传统安全模型有两大假设:
| 假设 | 传统应用 | Agent 应用 |
|---|---|---|
| 代码确定性 | 输入经过固定逻辑处理 | 输入直接进入"概率性大脑" |
| 输入可控性 | 输入是结构化参数 | 输入是自然语言,可注入指令 |
这就是"信任悖论":攻击者只需一条精心构造的 Prompt 就能劫持 Agent 行为,而防御者需要保护推理链路、工具接口、上下文记忆、输出通道的每一个环节。
OWASP 统计显示,83% 的生产级 Agent 在过去 12 个月内遭遇过至少一次 Prompt 注入或越权工具调用尝试,其中 31% 未被现有防护拦截。
二、OWASP Agentic Top 10 全景
OWASP 在 LLM Top 10 v2.0(2025)基础上,发布了 Agentic AI 应用十大风险,其中与 Agent 强相关的核心条目:
| 编号 | 风险 | 一句话理解 | 攻击场景 |
|---|---|---|---|
| Agentic 01 | Prompt Injection | 恶意指令注入提示词 | 网页/邮件/文档里藏注入指令 |
| Agentic 02 | Excessive Agency | 过度代理,权限过大 | Agent 越权执行高危操作 |
| Agentic 03 | Improper Output Handling | 输出处理不当 | Agent 输出被当代码/命令执行 |
| Agentic 04 | Insecure Tool Usage | 工具调用不安全 | 工具链被当作攻击跳板 |
| Agentic 05 | Data/Model Poisoning | 数据投毒 | 检索库里混入恶意文档 |
| Agentic 06 | Sensitive Information Disclosure | 敏感信息泄露 | Agent 把机密吐给用户 |
| Agentic 07 | Supply Chain | 供应链攻击 | 恶意 Skill/插件/MCP Server |
| Agentic 08 | Unbounded Consumption | 资源无上限消耗 | 无限循环调模型/工具 |
| Agentic 09 | Insecure Memory/Context | 记忆与上下文污染 | 长期记忆被篡改 |
| Agentic 10 | Improper AI Output & Compliance | 合规与审计缺失 | 无法追踪 Agent 干了什么 |
可以看到,前几篇讲过的 MCP(工具调用)、Context Engineering(上下文管理),在安全视角下全部变成了攻击面。这也是零信任在 Agent 时代成为刚需的原因。
三、零信任三大原则怎么落到 Agent 上?
零信任(Zero Trust)的经典三原则:永不信任、始终验证、最小权限。落到 Agent 上是这样:
┌─────────────────────────────────────────────────────────┐
│ Agent 零信任架构 │
│ │
│ 用户 ──> 认证 ──> LLM 推理 ──> 策略引擎 ──> 工具执行 │
│ │ │ │ │
│ │ ┌───────▼───────┐ │ │
│ │ │ 权限清单 │ │ │
│ │ │ 工具白名单 │ │ │
│ │ │ 参数校验器 │ │ │
│ │ │ 行为审计 │ │ │
│ │ └───────────────┘ │ │
│ ▼ ▼ │
│ ┌──────────┐ ┌──────────┐ │
│ │ 记忆/上下文 │ │ 沙箱执行 │ │
│ │ 隔离存储 │ │ 最小权限 │ │
│ └──────────┘ └──────────┘ │
└─────────────────────────────────────────────────────────┘
三句话:
- 永不信任:每个工具调用都要重新验证,不因"这是 Agent 内部调用"就放行
- 始终验证:LLM 想调工具?先过策略引擎检查意图、参数、权限
- 最小权限:Agent 只有一个"数字员工 ID",能干什么由权限清单说了算,不继承任何人的全部权限
四、逐条防御:从 OWASP 条目到 Spring 代码
4.1 防 Prompt Injection:输入消毒 + 意图识别
最经典的攻击。攻击者把指令藏在网页、邮件、文档里,Agent 检索到后就"变节"了。
java
// 1. 输入侧:把用户输入和系统指令用分隔符隔开
String userInput = sanitize(rawInput); // 去控制字符、超长截断
// 2. 意图侧:让模型先判断"用户到底想干嘛"再执行
ChatResponse intent = chatClient.prompt()
.system("你是意图识别器。只输出 JSON:{action, args, confidence}")
.user(userInput)
.call();
IntentResult result = parseIntent(intent);
if (result.confidence() < 0.9) {
throw new LowConfidenceException("意图不明确,拒绝执行");
}
关键点:不要直接信任 LLM 的输出。意图识别本身也是概率性的,所以还要配"危险动作拦截"(见 4.2)。
4.2 防 Excessive Agency:权限清单 + 危险动作拦截
OWASP 最强调的一条------Agent 权限过大。解决方案不是"让 Agent 更聪明",而是给 Agent 戴上手铐:
java
// 工具白名单 + 参数校验器
@Component
public class ToolGuard {
private static final Map<String, Set<String>> ALLOWED_PARAMS = Map.of(
"queryDatabase", Set.of("sql", "limit"),
"sendEmail", Set.of("to", "subject", "body"),
"executeScript", Set.of() // 默认禁用
);
// 危险动作清单:任何 Agent 都不能直接干
private static final List<String> BLOCKED_ACTIONS = List.of(
"DELETE", "DROP", "TRUNCATE", "rm -rf", "grant", "revoke"
);
public boolean check(String toolName, Map<String, Object> args) {
if (!ALLOWED_PARAMS.containsKey(toolName)) return false; // 非白名单工具
if (!args.keySet().containsAll(ALLOWED_PARAMS.get(toolName))) return false; // 参数越界
String raw = String.join(" ", args.values().toString());
if (BLOCKED_ACTIONS.stream().anyMatch(raw::contains)) return false; // 危险词
return true;
}
}
关键原则:危险操作(删库、发款、高权限命令)必须走"人工确认"通道,Agent 只能发起请求,不能直接执行。
4.3 防工具滥用:工具入口做鉴权 + 审计
工具是 Agent 的"手",也是攻击者的跳板。每个工具入口都要做三件事:认证、授权、审计。
java
@RestController
public class ToolGateway {
private final ToolPermission permission;
private final AuditLog auditLog;
@PostMapping("/api/agent/tools/{toolName}")
public ResponseEntity<?> invoke(
@PathVariable String toolName,
@RequestBody ToolRequest request,
@RequestHeader("X-Agent-Token") String agentToken) {
// 1. 认证:Agent 必须持合法令牌
if (!agentTokenService.verify(agentToken)) {
return ResponseEntity.status(401).build();
}
// 2. 授权:令牌对应该 Agent 的权限域
AgentIdentity identity = agentTokenService.resolve(agentToken);
if (!identity.canAccess(toolName)) {
auditLog.warn("越权工具调用被拦截", identity, toolName);
return ResponseEntity.status(403).build();
}
// 3. 参数校验 + 危险动作拦截
if (!permission.check(toolName, request.args())) {
auditLog.warn("参数越界被拦截", identity, toolName, request.args());
return ResponseEntity.status(400).build();
}
// 4. 审计记录(零信任的可追踪基础)
auditLog.info("tool_call", identity, toolName, request.args());
return toolExecutor.execute(toolName, request.args());
}
}
4.4 防检索投毒:证据可信度分级
RAG 是注入重灾区------攻击者把恶意文档混进检索库,Agent 读到就中毒。防御思路:对证据分级。
arduino
检索到的文档 ──> 来源可信度评分 ──> 高可信:直接作为证据
│
├── 中可信:标注"可能被污染",降低权重
└── 低可信:不注入,只提示"存在参考"
java
public List<Document> safeRetrieve(String query, String userRole) {
List<Document> docs = vectorStore.similaritySearch(query, 10);
return docs.stream()
.filter(d -> trustScore(d, userRole) >= 0.7) // 可信度过滤
.peek(d -> d.getMetadata().put("source", classify(d)))
.limit(3)
.toList();
}
4.5 防敏感信息泄露:输出过滤 + 脱敏
Agent 输出里可能带出数据库隐私。在输出回给用户前,加一道"出口安检":
java
public String safeReply(String raw) {
// 1. 正则/规则脱敏:手机号、身份证、银行卡
String masked = maskSensitive(raw);
// 2. 权限过滤:用户无权查看的字段直接替换为"权限不足"
if (!user.hasPermission("seeSalary")) {
masked = masked.replaceAll("(?<=收入:)[\\d,.]+元", "***");
}
// 3. 可选:让 LLM 复审一遍输出是否含敏感信息
return masked;
}
4.6 防资源耗尽:限流 + 循环熔断
Agent 跑起来可能自己陷入死循环(无限调工具)。加熔断器和令牌桶:
java
@Component
public class AgentGuard {
private final RateLimiter perUserLimiter; // 令牌桶
private final AtomicInteger toolCallCount = new AtomicInteger();
private static final int MAX_TOOL_CALLS_PER_TASK = 20; // 单任务上限
public boolean tryAcquire(String userId) {
// 单用户限流
if (!perUserLimiter.tryAcquire(userId)) return false;
// 单任务工具调用上限
if (toolCallCount.incrementAndGet() > MAX_TOOL_CALLS_PER_TASK) {
throw new AgentRunawayException("工具调用超限,已熔断");
}
return true;
}
}
4.7 记忆安全:Agent 的"记忆"要隔离、校验、可清除
长期记忆被污染是隐蔽攻击。原则:
- 隔离:每个用户的记忆独立存储,不共享
- 校验:写入记忆前校验格式、敏感信息、注入特征
- 可清除:用户有权一键清空自己的记忆(合规要求)
java
// 写入记忆前的"安检门"
public void saveMemory(String userId, String memory) {
if (containsInjectionPattern(memory)) {
auditLog.warn("记忆写入疑似注入", userId);
memory = sanitize(memory);
}
if (containsSensitive(memory)) {
throw new MemoryRejectedException("记忆含敏感信息,禁止写入");
}
memoryStore.save(userId, memory);
}
五、完整零信任网关:把上面全部串起来
一个生产级的 Agent 请求流程:
arduino
用户输入
│
▼
┌─────────────────────────────────────────────┐
│ 1. 输入消毒:分隔符隔离、控制字符清洗 │
│ 2. 意图识别:先判"用户想干什么" │
│ 3. 策略引擎:工具白名单 + 参数校验 + 危险动作 │
│ 4. 权限校验:数字身份 + 最小权限 │
│ 5. 证据分级:检索文档可信度过滤 │
│ 6. 执行沙箱:工具隔离执行,审计全程记录 │
│ 7. 输出安检:敏感信息过滤 + 内容复审 │
│ 8. 熔断限流:资源耗尽保护 │
└─────────────────────────────────────────────┘
│
▼
工具执行 / 人工审批通道
java
public String guardedChat(String userId, String rawInput) {
// 1. 输入消毒
String clean = sanitizeInput(rawInput);
// 2. 意图识别(低置信直接拒绝)
Intent intent = recognizeIntent(clean);
// 3. 策略检查(工具+参数+危险动作)
if (!policyEngine.check(intent.toolName(), intent.args())) {
return "该操作被策略拦截,如需执行请联系管理员审批";
}
// 4. 执行 + 审计
ToolResult result = toolExecutor.execute(intent, identity);
// 5. 输出安检
return outputFilter.sanitize(result.toString(), identity);
}
六、零信任不是"加安全",而是架构方式
2026 年的安全共识已经转向:
| 传统安全 | 零信任安全 |
|---|---|
| 内网可信,外网不可信 | 内网外网都不可信 |
| 一次认证,长期信任 | 每次调用都要验证 |
| 用户权限复用 | Agent 用独立数字身份 |
| 事后审计 | 事前拦截 + 实时检测 |
| 攻防对抗 | 纵深防御 + 可验证 |
对开发者来说,最实用的一句话建议:把你的 Agent 当成一个"未知数量的高危权限持有者"来设计------所有工具入口都要有认证、授权、参数校验、危险动作拦截和全程审计,而不是默认"模型很聪明不会乱来"。
七、系列总结(收官)
至此,Agent 前沿热点系列收官。回看这四篇,其实是一条完整的 Agent 落地链路:
arduino
第1篇 MCP 协议 ──▶ 让 Agent 能"够得着"工具
第2篇 A2A 协议 ──▶ 让 Agent 能"对话"协作
第3篇 Context ──▶ 让 Agent 有"好用的脑子"
第4篇 零信任安全 ──▶ 让 Agent 能"安全地干活"
前 13 篇基础系列讲"Agent 是什么、怎么搭",实战 2 篇讲"我真实怎么用",前沿热点 4 篇讲"2026 年最热的工程话题"。从理解、到使用、到前沿,这条技术路径走完了。
Agent 已经是 2026 年最重要的工程话题之一。愿你手里的 Agent 不仅强大,而且可控。