深色模式
越权与工具滥用防护
摘要:当 LLM 从"聊天"升级为"能调工具办事"的 Agent,风险重心从内容安全转向动作安全。OWASP LLM06(Excessive Agency,过度授权)指出:模型被赋予过多功能、权限或自主性时,一次被影响的调用就能造成真实损害(删库、转账、发邮件)。本文给出工具层最小权限、沙箱与人工审批的可落地方案,适用所有 function calling / MCP 架构。模型/版本:Claude 4.x、GPT-4o + 工具调用、以及自托管 Agent 框架均适用。
适用版本与前提
- 架构:Agent / Orchestrator + 工具(MCP server、OpenAI function calling、LangChain tools 等)。
- 前提:可定义工具清单、可设置 per-tool 权限与确认策略、可限制调用频率与预算。
模型不是授权主体
LLM 本身没有身份与权限概念——它只是生成"想调哪个工具、传什么参数"。真正的权限边界必须由外围系统强制执行:工具的凭据、作用域、确认门都在服务端,模型只是建议者。把权限交给模型 = 把权限交给任意能注入它的人。
核心概念:三种过度授权
| 类型 | 说明 | 例子 |
|---|---|---|
| 功能过度 | 工具能力超出任务需要 | 本只需读文件,却给了写/删 |
| 权限过度 | 工具能访问本不该访问的数据 | 本应只看当前用户文件,却能看所有人 |
| 自主性过度 | 无需确认即可产生外部影响 | 模型自行决定删除用户文件/发起转账 |
架构:工具调用的信任边界
生产实践:最小权限 + 审批 + 预算
1) 工具清单最小权限(allowlist)
只暴露任务必需的 tools;用 resourceNames 思路把工具作用域收敛到具体资源。
yaml
# tools_policy.yml
tools:
- name: read_doc
scope: "tenant:{tenant_id}:docs:read"
confirm: false
- name: send_email
scope: "mail:send"
confirm: true # 对外发送必须人工确认
- name: delete_file
scope: "user:{user_id}:files:delete"
confirm: true
- name: transfer_funds
scope: "finance:transfer"
confirm: true
max_amount: 1000 # 单笔上限, 超额升级审批
deny_by_default: true # 未列出的工具一律不可调1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2) 高风险动作人工确认门
对"写/删/对外发送/财务"类工具,在网关层强制 confirm: true,把待执行参数展示给人类审批,而非模型自决。
python
def dispatch(tool_call: dict, user: str) -> dict:
policy = TOOL_POLICY[tool_call["name"]]
if not policy.get("allow", False):
raise PermissionError(f"tool {tool_call['name']} not allowed")
if policy.get("confirm"):
approved = request_human_approval(user, tool_call) # 阻塞等待人类
if not approved:
return {"ok": False, "reason": "rejected_by_human"}
return run_tool(tool_call, scope=policy["scope"])1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
3) 调用预算与死循环熔断(防 LLM10 + 成本失控)
Agent 的 reAct 循环必须设硬上限,否则注入或模型失误可造成无限调用。
python
BUDGET = {"max_tool_calls_per_session": 20, "max_tokens_per_session": 200_000}
def agent_loop(user_input):
calls = 0
while calls < BUDGET["max_tool_calls_per_session"]:
action = llm.decide(...)
if action.is_final:
return action.answer
dispatch(action.tool_call, user=...)
calls += 1
raise RuntimeError("budget exhausted: possible loop") # 熔断, 转人工1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
操作步骤:把策略接进 MCP
bash
# 仅允许列出的 MCP tools 暴露给 Agent(MCP Tool Allowlisting)
# 参考 claudereadiness 的 allowlist 模式: 不要 expose 全部可用 tools
cat > mcp_policy.json <<'JSON'
{
"allow": ["read_doc", "search_web"],
"deny": ["fs_write", "shell_exec", "db_drop"]
}
JSON
# 在编排层加载该 policy, 启动 Agent
python -m your_agent --mcp-policy mcp_policy.json1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
验证
bash
# 越权用例: 模型试图调用 deny 列表中的工具, 应被网关拒绝
pytest tests/redteam/test_tool_abuse.py
# 覆盖: 直接请求删库 / 跨用户读文件 / 诱导发送邮件 / 触发死循环1
2
3
2
3
回滚与清理
收紧权限会中断正常业务流程
deny_by_default + 最小 allowlist 上线前,先在 staging 跑全量真实业务路径,确认没有"业务其实需要但没列入"的工具。遗漏会导致线上功能不可用。保留旧 policy 以便一键回滚。
故障排查
- Q:模型频繁绕过确认门? 确认门必须在服务端强制执行,不能仅靠 system prompt 里写"请先询问用户"。提示可被注入绕过,网关校验不可绕过。
- Q:预算总是很快耗尽? 多为 prompt 设计导致模型反复重试同一工具。检查是否给了足够的"终止信号"(任务完成即返回),并适当提高
max_tool_calls同时监控循环模式。
安全与合规
- LLM06 本质是传统"Broken Access Control"在 Agent 层的映射:最小权限、零信任同样适用。
- 真实案例:2026-01 Anthropic MCP Git Server 三处漏洞(CVE-2025-68143/68144/68145),经仓库内容提示注入可实现路径遍历与 RCE——印证工具层必须最小权限 + 沙箱
[未实测:未复现]。 - EU AI Act 对"充分网络安全保护"的要求,把工具隔离纳入合规证据链。
成本 / 性能
- 人工确认门增加交互延迟(需等待人),但对不可逆动作不可或缺——这是"安全优先于体验"的典型取舍。
- 调用预算直接防止无限循环产生的天价 token 账单(本期重点)。一个无上限 Agent 在 reAct 死循环下数小时可产生数千美元费用。