第12章 权限系统 —— Deny→ask→allow的安全边界
目录
上一篇我们剖析了工具系统的分发机制。本章我们看权限系统——保护安全的三级边界。
权限系统是什么
一句话定义:安全边界和审批流程——控制哪些操作可以自动执行,哪些需要用户确认。
Permissions = 安全边界系统 定位:Harness 的管理层核心,保护用户环境
图表
代码
graph LR
A[工具调用请求] --> B{权限检查}
B -->|deny| C[❌ 禁止执行
返回错误]
B -->|ask| D[⚠️ 请求审批
等待用户确认]
B -->|allow| E[✅ 自动执行
返回结果]graph LR
A[工具调用请求] --> B{权限检查}
B -->|deny| C[❌ 禁止执行
返回错误]
B -->|ask| D[⚠️ 请求审批
等待用户确认]
B -->|allow| E[✅ 自动执行
返回结果]graph LR
A[工具调用请求] --> B{权限检查}
B -->|deny| C[❌ 禁止执行
返回错误]
B -->|ask| D[⚠️ 请求审批
等待用户确认]
B -->|allow| E[✅ 自动执行
返回结果]graph LR
A[工具调用请求] --> B{权限检查}
B -->|deny| C[❌ 禁止执行<br/>返回错误]
B -->|ask| D[⚠️ 请求审批<br/>等待用户确认]
B -->|allow| E[✅ 自动执行<br/>返回结果]核心机制:
- deny:禁止执行,返回错误
- ask:请求审批,等待用户确认
- allow:自动执行,无需用户干预
权限三级模式
三级对比
| 模式 | 行为 | 适用场景 | 示例 |
|---|---|---|---|
| deny | ❌ 禁止执行 | 危险操作 | 删除系统文件、访问密钥 |
| ask | ⚠️ 请求审批 | 中等风险 | git push、npm install、rm -rf |
| allow | ✅ 自动执行 | 安全操作 | Read、Glob、Grep |
图表
代码
graph TB
subgraph Security["安全分级"]
S1[deny
危险操作
禁止]
S2[ask
中等风险
审批]
S3[allow
安全操作
自动]
end
S1 --> S2 --> S3graph TB
subgraph Security["安全分级"]
S1[deny
危险操作
禁止]
S2[ask
中等风险
审批]
S3[allow
安全操作
自动]
end
S1 --> S2 --> S3graph TB
subgraph Security["安全分级"]
S1[deny
危险操作
禁止]
S2[ask
中等风险
审批]
S3[allow
安全操作
自动]
end
S1 --> S2 --> S3graph TB
subgraph Security["安全分级"]
S1[deny<br/>危险操作<br/>禁止]
S2[ask<br/>中等风险<br/>审批]
S3[allow<br/>安全操作<br/>自动]
end
S1 --> S2 --> S3deny —— 禁止执行
触发场景:
- 删除系统关键文件(/bin、/usr、/etc)
- 访问敏感文件(.env、credentials.json)
- 执行危险命令(rm -rf /、sudo)
- 访问私有密钥(SSH keys、API keys)
规则示例:
{
"permissions": {
"deny": [
{
"tool": "Bash",
"command": "rm -rf /",
"reason": "禁止删除根目录"
},
{
"tool": "Read",
"file_path": ".env",
"reason": "禁止访问环境变量文件"
},
{
"tool": "Read",
"file_path": "*credentials.json",
"reason": "禁止访问凭证文件"
}
]
}
}ask —— 请求审批
触发场景:
- Git 操作(git push、git commit)
- 安装依赖(npm install、pip install)
- 删除文件(rm -rf、unlink)
- 网络请求(WebFetch 到敏感 URL)
规则示例:
{
"permissions": {
"ask": [
{
"tool": "Bash",
"command": "git push",
"reason": "推送代码需要确认"
},
{
"tool": "Bash",
"command": "npm install",
"reason": "安装依赖可能影响环境"
},
{
"tool": "Bash",
"command": "rm -rf",
"reason": "删除文件需要确认"
}
]
}
}审批流程:
图表
代码
graph LR
A[工具调用
ask 规则匹配] --> B[暂停执行]
B --> C[显示审批界面]
C --> D{用户响应}
D -->|批准| E[执行工具]
D -->|拒绝| F[返回拒绝信息]
E --> G[继续 Loop]
F --> H[Model 收到拒绝信息]graph LR
A[工具调用
ask 规则匹配] --> B[暂停执行]
B --> C[显示审批界面]
C --> D{用户响应}
D -->|批准| E[执行工具]
D -->|拒绝| F[返回拒绝信息]
E --> G[继续 Loop]
F --> H[Model 收到拒绝信息]graph LR
A[工具调用
ask 规则匹配] --> B[暂停执行]
B --> C[显示审批界面]
C --> D{用户响应}
D -->|批准| E[执行工具]
D -->|拒绝| F[返回拒绝信息]
E --> G[继续 Loop]
F --> H[Model 收到拒绝信息]graph LR
A[工具调用<br/>ask 规则匹配] --> B[暂停执行]
B --> C[显示审批界面]
C --> D{用户响应}
D -->|批准| E[执行工具]
D -->|拒绝| F[返回拒绝信息]
E --> G[继续 Loop]
F --> H[Model 收到拒绝信息]allow —— 自动执行
触发场景:
- 文件读取(Read)
- 文件搜索(Glob、Grep)
- 网络搜索(WebSearch)
- 页面浏览(Browser_snapshot)
规则示例:
{
"permissions": {
"allow": [
{
"tool": "Read",
"reason": "读取文件安全"
},
{
"tool": "Glob",
"reason": "搜索文件路径安全"
},
{
"tool": "Grep",
"reason": "搜索文件内容安全"
},
{
"tool": "WebSearch",
"reason": "网络搜索安全"
}
]
}
}权限规则设计
规则匹配机制
匹配优先级:
图表
代码
graph LR
A[工具调用] --> B{匹配 deny 规则}
B -->|匹配| C[deny
禁止执行]
B -->|不匹配| D{匹配 ask 规则}
D -->|匹配| E[ask
请求审批]
D -->|不匹配| F{匹配 allow 规则}
F -->|匹配| G[allow
自动执行]
F -->|不匹配| H[默认 ask
请求审批]graph LR
A[工具调用] --> B{匹配 deny 规则}
B -->|匹配| C[deny
禁止执行]
B -->|不匹配| D{匹配 ask 规则}
D -->|匹配| E[ask
请求审批]
D -->|不匹配| F{匹配 allow 规则}
F -->|匹配| G[allow
自动执行]
F -->|不匹配| H[默认 ask
请求审批]graph LR
A[工具调用] --> B{匹配 deny 规则}
B -->|匹配| C[deny
禁止执行]
B -->|不匹配| D{匹配 ask 规则}
D -->|匹配| E[ask
请求审批]
D -->|不匹配| F{匹配 allow 规则}
F -->|匹配| G[allow
自动执行]
F -->|不匹配| H[默认 ask
请求审批]graph LR
A[工具调用] --> B{匹配 deny 规则}
B -->|匹配| C[deny<br/>禁止执行]
B -->|不匹配| D{匹配 ask 规则}
D -->|匹配| E[ask<br/>请求审批]
D -->|不匹配| F{匹配 allow 规则}
F -->|匹配| G[allow<br/>自动执行]
F -->|不匹配| H[默认 ask<br/>请求审批]匹配规则:
| 匹配维度 | 说明 | 示例 |
|---|---|---|
| 工具名称 | 匹配 tool_name | "tool": "Bash" |
| 命令匹配 | 匹配命令前缀 | "command": "git push" |
| 文件路径匹配 | 匹配文件路径模式 | "file_path": "*.env" |
| 参数匹配 | 匹配参数值 | "url": "https://sensitive.com" |
匹配顺序:
- deny 规则优先(最严格)
- ask 规则其次(中等)
- allow 规则最后(最宽松)
- 无匹配时默认 ask(保守策略)
规则配置文件
JSON 配置示例:
{
"permissions": {
"deny": [
{"tool": "Bash", "command": "rm -rf /"},
{"tool": "Read", "file_path": ".env"},
{"tool": "Read", "file_path": "*credentials*"}
],
"ask": [
{"tool": "Bash", "command": "git push"},
{"tool": "Bash", "command": "npm install"},
{"tool": "Bash", "command": "rm -rf"}
],
"allow": [
{"tool": "Read"},
{"tool": "Glob"},
{"tool": "Grep"},
{"tool": "WebSearch"}
]
}
}规则模式匹配
通配符支持:
| 模式 | 说明 | 示例 |
|---|---|---|
* | 匹配任意字符 | "file_path": "*.env" 匹配所有 .env 文件 |
** | 匹配任意路径 | "file_path": "**/*.json" 匹配所有 JSON 文件 |
? | 匹配单个字符 | "command": "git ?" 匹配 git add, git commit 等 |
| ` | ` | 或匹配 |
正则匹配:
{
"permissions": {
"deny": [
{
"tool": "Bash",
"command": "^rm -rf.*", // 正则:匹配所有 rm -rf
"reason": "禁止所有删除操作"
}
]
}
}权限检查流程
完整流程
图表
代码
sequenceDiagram
participant Loop as Agent Loop
participant PermCheck as 权限检查器
participant Rules as 规则配置
participant User as 用户审批界面
participant ToolExec as 工具执行器
Loop->>PermCheck: 工具调用请求
PermCheck->>Rules: 检查 deny 规则
Rules-->>PermCheck: deny 规则匹配?
alt deny 匹配
PermCheck-->>Loop: deny,返回错误
else deny 不匹配
PermCheck->>Rules: 检查 ask 规则
Rules-->>PermCheck: ask 规则匹配?
alt ask 匹配
PermCheck->>User: 显示审批界面
User-->>PermCheck: 用户确认
alt 用户批准
PermCheck->>ToolExec: 执行工具
ToolExec-->>PermCheck: 返回结果
PermCheck-->>Loop: 返回工具输出
else 用户拒绝
PermCheck-->>Loop: 返回拒绝信息
end
else ask 不匹配
PermCheck->>Rules: 检查 allow 规则
Rules-->>PermCheck: allow 规则匹配?
alt allow 匹配
PermCheck->>ToolExec: 执行工具
ToolExec-->>PermCheck: 返回结果
PermCheck-->>Loop: 返回工具输出
else 无匹配
PermCheck->>User: 默认 ask
User-->>PermCheck: 用户确认
PermCheck-->>Loop: 返回结果
end
end
endsequenceDiagram
participant Loop as Agent Loop
participant PermCheck as 权限检查器
participant Rules as 规则配置
participant User as 用户审批界面
participant ToolExec as 工具执行器
Loop->>PermCheck: 工具调用请求
PermCheck->>Rules: 检查 deny 规则
Rules-->>PermCheck: deny 规则匹配?
alt deny 匹配
PermCheck-->>Loop: deny,返回错误
else deny 不匹配
PermCheck->>Rules: 检查 ask 规则
Rules-->>PermCheck: ask 规则匹配?
alt ask 匹配
PermCheck->>User: 显示审批界面
User-->>PermCheck: 用户确认
alt 用户批准
PermCheck->>ToolExec: 执行工具
ToolExec-->>PermCheck: 返回结果
PermCheck-->>Loop: 返回工具输出
else 用户拒绝
PermCheck-->>Loop: 返回拒绝信息
end
else ask 不匹配
PermCheck->>Rules: 检查 allow 规则
Rules-->>PermCheck: allow 规则匹配?
alt allow 匹配
PermCheck->>ToolExec: 执行工具
ToolExec-->>PermCheck: 返回结果
PermCheck-->>Loop: 返回工具输出
else 无匹配
PermCheck->>User: 默认 ask
User-->>PermCheck: 用户确认
PermCheck-->>Loop: 返回结果
end
end
endsequenceDiagram
participant Loop as Agent Loop
participant PermCheck as 权限检查器
participant Rules as 规则配置
participant User as 用户审批界面
participant ToolExec as 工具执行器
Loop->>PermCheck: 工具调用请求
PermCheck->>Rules: 检查 deny 规则
Rules-->>PermCheck: deny 规则匹配?
alt deny 匹配
PermCheck-->>Loop: deny,返回错误
else deny 不匹配
PermCheck->>Rules: 检查 ask 规则
Rules-->>PermCheck: ask 规则匹配?
alt ask 匹配
PermCheck->>User: 显示审批界面
User-->>PermCheck: 用户确认
alt 用户批准
PermCheck->>ToolExec: 执行工具
ToolExec-->>PermCheck: 返回结果
PermCheck-->>Loop: 返回工具输出
else 用户拒绝
PermCheck-->>Loop: 返回拒绝信息
end
else ask 不匹配
PermCheck->>Rules: 检查 allow 规则
Rules-->>PermCheck: allow 规则匹配?
alt allow 匹配
PermCheck->>ToolExec: 执行工具
ToolExec-->>PermCheck: 返回结果
PermCheck-->>Loop: 返回工具输出
else 无匹配
PermCheck->>User: 默认 ask
User-->>PermCheck: 用户确认
PermCheck-->>Loop: 返回结果
end
end
endsequenceDiagram
participant Loop as Agent Loop
participant PermCheck as 权限检查器
participant Rules as 规则配置
participant User as 用户审批界面
participant ToolExec as 工具执行器
Loop->>PermCheck: 工具调用请求
PermCheck->>Rules: 检查 deny 规则
Rules-->>PermCheck: deny 规则匹配?
alt deny 匹配
PermCheck-->>Loop: deny,返回错误
else deny 不匹配
PermCheck->>Rules: 检查 ask 规则
Rules-->>PermCheck: ask 规则匹配?
alt ask 匹配
PermCheck->>User: 显示审批界面
User-->>PermCheck: 用户确认
alt 用户批准
PermCheck->>ToolExec: 执行工具
ToolExec-->>PermCheck: 返回结果
PermCheck-->>Loop: 返回工具输出
else 用户拒绝
PermCheck-->>Loop: 返回拒绝信息
end
else ask 不匹配
PermCheck->>Rules: 检查 allow 规则
Rules-->>PermCheck: allow 规则匹配?
alt allow 匹配
PermCheck->>ToolExec: 执行工具
ToolExec-->>PermCheck: 返回结果
PermCheck-->>Loop: 返回工具输出
else 无匹配
PermCheck->>User: 默认 ask
User-->>PermCheck: 用户确认
PermCheck-->>Loop: 返回结果
end
end
end权限检查实现
# 权限检查实现
def check_permission(tool_name, tool_args, rules):
# 1. 检查 deny 规则
for rule in rules["deny"]:
if match_rule(tool_name, tool_args, rule):
return "deny", rule["reason"]
# 2. 检查 ask 规则
for rule in rules["ask"]:
if match_rule(tool_name, tool_args, rule):
return "ask", rule["reason"]
# 3. 检查 allow 规则
for rule in rules["allow"]:
if match_rule(tool_name, tool_args, rule):
return "allow", None
# 4. 无匹配时默认 ask(保守策略)
return "ask", "默认需要审批"
# 规则匹配
def match_rule(tool_name, tool_args, rule):
# 工具名称匹配
if rule.get("tool") and rule["tool"] != tool_name:
return False
# 命令匹配
if rule.get("command"):
command = tool_args.get("command", "")
if not pattern_match(command, rule["command"]):
return False
# 文件路径匹配
if rule.get("file_path"):
file_path = tool_args.get("file_path", "")
if not pattern_match(file_path, rule["file_path"]):
return False
return True用户审批界面
审批提示格式
⚠️ 权限审批请求
工具: Bash
命令: git push origin main
原因: 推送代码需要确认
是否批准执行?
[批准] [拒绝] [查看详情]审批选项
| 选项 | 行为 | 后果 |
|---|---|---|
| 批准 | 执行工具 | 工具执行,返回结果 |
| 拒绝 | 拒绝执行 | 返回拒绝信息,Model 调整策略 |
| 查看详情 | 显示详细信息 | 查看工具参数、风险评估 |
批量审批
问题:连续多个 ask 工具调用,频繁打断用户。
解决方案:批量审批
图表
代码
graph LR
A[连续 ask 工具调用] --> B[暂停执行]
B --> C[收集所有请求]
C --> D[显示批量审批界面]
D --> E{用户响应}
E -->|全部批准| F[执行所有工具]
E -->|逐个审批| G[逐个确认]graph LR
A[连续 ask 工具调用] --> B[暂停执行]
B --> C[收集所有请求]
C --> D[显示批量审批界面]
D --> E{用户响应}
E -->|全部批准| F[执行所有工具]
E -->|逐个审批| G[逐个确认]graph LR
A[连续 ask 工具调用] --> B[暂停执行]
B --> C[收集所有请求]
C --> D[显示批量审批界面]
D --> E{用户响应}
E -->|全部批准| F[执行所有工具]
E -->|逐个审批| G[逐个确认]graph LR
A[连续 ask 工具调用] --> B[暂停执行]
B --> C[收集所有请求]
C --> D[显示批量审批界面]
D --> E{用户响应}
E -->|全部批准| F[执行所有工具]
E -->|逐个审批| G[逐个确认]批量审批界面:
⚠️ 批量权限审批请求
1. Bash: git push origin main
2. Bash: npm install
3. Write: /src/new.ts
[全部批准] [逐个审批] [全部拒绝]权限配置级别
配置级别对比
| 配置级别 | 位置 | 影响范围 | 优先级 |
|---|---|---|---|
| 全局配置 | ~/.claude/settings.json | 所有项目 | 最高 |
| 项目配置 | .claude/settings.json | 当前项目 | 中 |
| 临时配置 | 会话内临时设置 | 当前会话 | 最低 |
图表
代码
graph TB
Global[全局配置
~/.claude/settings.json
所有项目] --> Project[项目配置
.claude/settings.json
当前项目]
Project --> Session[临时配置
会话内设置
当前会话]
Global[优先级最高]
Project[优先级中]
Session[优先级最低]graph TB
Global[全局配置
~/.claude/settings.json
所有项目] --> Project[项目配置
.claude/settings.json
当前项目]
Project --> Session[临时配置
会话内设置
当前会话]
Global[优先级最高]
Project[优先级中]
Session[优先级最低]graph TB
Global[全局配置
~/.claude/settings.json
所有项目] --> Project[项目配置
.claude/settings.json
当前项目]
Project --> Session[临时配置
会话内设置
当前会话]
Global[优先级最高]
Project[优先级中]
Session[优先级最低]graph TB
Global[全局配置<br/>~/.claude/settings.json<br/>所有项目] --> Project[项目配置<br/>.claude/settings.json<br/>当前项目]
Project --> Session[临时配置<br/>会话内设置<br/>当前会话]
Global[优先级最高]
Project[优先级中]
Session[优先级最低]配置示例
全局配置:
// ~/.claude/settings.json
{
"permissions": {
"deny": [
{"tool": "Bash", "command": "rm -rf /"}
],
"allow": [
{"tool": "Read"},
{"tool": "Glob"}
]
}
}项目配置:
// .claude/settings.json
{
"permissions": {
"ask": [
{"tool": "Bash", "command": "git push"} // 项目级 ask
]
}
}权限系统的设计格言
格言
“先划边界, 再给自由” —— 先判断操作能不能做,要不要问用户
设计要点
| 要点 | 说明 | 实现方式 |
|---|---|---|
| 默认 deny | 未知操作默认禁止 | 无匹配时默认 ask |
| 最小权限 | 只授予必要权限 | 精确匹配规则 |
| 信任边界 | 区分可信/不可信操作 | 分级权限模式 |
| 透明审批 | 审批信息清晰完整 | 显示工具、参数、原因 |
图表
代码
graph TB
subgraph Philosophy["权限设计哲学"]
P1[默认 deny
保守策略]
P2[最小权限
只授予必要]
P3[信任边界
分级权限]
P4[透明审批
信息清晰]
endgraph TB
subgraph Philosophy["权限设计哲学"]
P1[默认 deny
保守策略]
P2[最小权限
只授予必要]
P3[信任边界
分级权限]
P4[透明审批
信息清晰]
endgraph TB
subgraph Philosophy["权限设计哲学"]
P1[默认 deny
保守策略]
P2[最小权限
只授予必要]
P3[信任边界
分级权限]
P4[透明审批
信息清晰]
endgraph TB
subgraph Philosophy["权限设计哲学"]
P1[默认 deny<br/>保守策略]
P2[最小权限<br/>只授予必要]
P3[信任边界<br/>分级权限]
P4[透明审批<br/>信息清晰]
end权限系统 vs 无权限系统
对比
| 维度 | 权限系统 | 无权限系统 |
|---|---|---|
| 安全性 | ✅ 高(危险操作需审批) | ❌ 低(任何操作自动执行) |
| 用户体验 | ⚠️ 中(需要审批确认) | ✅ 高(无需打断) |
| 误操作风险 | ✅ 低(有保护) | ❌ 高(无保护) |
| 适用场景 | 生产环境、重要项目 | 实验、测试环境 |
图表
代码
graph TB
subgraph WithPerm["有权限系统"]
W1[安全]
W2[误操作风险低]
W3[需用户确认]
end
subgraph WithoutPerm["无权限系统"]
O1[不安全]
O2[误操作风险高]
O3[无需打断]
end
style WithPerm fill:#E0FFE0
style WithoutPerm fill:#FFE0E0graph TB
subgraph WithPerm["有权限系统"]
W1[安全]
W2[误操作风险低]
W3[需用户确认]
end
subgraph WithoutPerm["无权限系统"]
O1[不安全]
O2[误操作风险高]
O3[无需打断]
end
style WithPerm fill:#E0FFE0
style WithoutPerm fill:#FFE0E0graph TB
subgraph WithPerm["有权限系统"]
W1[安全]
W2[误操作风险低]
W3[需用户确认]
end
subgraph WithoutPerm["无权限系统"]
O1[不安全]
O2[误操作风险高]
O3[无需打断]
end
style WithPerm fill:#E0FFE0
style WithoutPerm fill:#FFE0E0graph TB
subgraph WithPerm["有权限系统"]
W1[安全]
W2[误操作风险低]
W3[需用户确认]
end
subgraph WithoutPerm["无权限系统"]
O1[不安全]
O2[误操作风险高]
O3[无需打断]
end
style WithPerm fill:#E0FFE0
style WithoutPerm fill:#FFE0E0权限系统的最佳实践
推荐配置
保守配置(推荐生产环境):
{
"permissions": {
"deny": [
{"tool": "Bash", "command": "rm -rf /"},
{"tool": "Bash", "command": "sudo"},
{"tool": "Read", "file_path": ".env"},
{"tool": "Read", "file_path": "*credentials*"}
],
"ask": [
{"tool": "Bash", "command": "git push"},
{"tool": "Bash", "command": "npm install"},
{"tool": "Bash", "command": "pip install"},
{"tool": "Write"},
{"tool": "Edit"}
],
"allow": [
{"tool": "Read"},
{"tool": "Glob"},
{"tool": "Grep"},
{"tool": "WebSearch"}
]
}
}宽松配置(推荐测试环境):
{
"permissions": {
"deny": [
{"tool": "Bash", "command": "rm -rf /"}
],
"allow": [
{"tool": "Read"},
{"tool": "Write"},
{"tool": "Edit"},
{"tool": "Bash"},
{"tool": "Glob"},
{"tool": "Grep"}
]
}
}权限审计
审计内容:
- 记录所有权限决策(deny/ask/allow)
- 记录审批结果(批准/拒绝)
- 分析频繁 ask 工具(可能需要调整权限)
审计日志:
2026-05-21 10:30:15 | Bash: git push | ask | 批准
2026-05-21 10:30:20 | Write: /src/new.ts | ask | 批准
2026-05-21 10:30:25 | Bash: rm -rf temp | ask | 拒绝本章小结
- 权限系统定义:安全边界和审批流程
- 三级模式:deny(禁止)、ask(审批)、allow(自动)
- 规则匹配:deny→ask→allow→默认ask
- 规则配置:工具名称、命令、文件路径、参数匹配
- 审批流程:暂停执行→显示界面→用户确认→执行或拒绝
- 配置级别:全局→项目→临时,优先级递减
- 设计格言:先划边界,再给自由;默认deny,最小权限
- 最佳实践:生产环境保守配置,测试环境宽松配置
- 权限审计:记录决策,分析频繁 ask
预告:下一篇我们深入上下文管理——自动注入、压缩与惰性加载。
相关内容
- 第01章 Agent 的 70 年简史 —— 从符号推理到深度学习
- 第02章 LLM 时代的 Agent 革命 —— 2023-2026 爆发期
- 第03章 Harness 概念溯源 —— "模型是大脑,Harness是身体"
- 第04章 Harness 核心架构 —— 四层模型详解
- 第05章 Harness vs Agent vs Model —— 三者关系辨析
如果这篇文章对你有帮助,欢迎请我喝杯咖啡 ☕
支付宝
微信