AI 的边界在哪里:权限决策体系与 14 步授权逻辑

《Claude Code 架构解密》读书笔记 · 第06篇
对应章节:第5章前半(5.1-5.4)— 权限模型:在自动化与安全之间走钢丝(p.112-118)


导语

给 AI Agent 一把剪刀——它能帮你裁布,也可能剪断电线。真正的问题不是"要不要给",而是"怎么给,给多少,什么时候收回"。Claude Code 的权限系统(约 20 个模块、5000+ 行代码)用四级信任、八层规则源、14 步决策树,在"每次都弹窗确认"和"全部自动放行"之间找到了可行的中间路。本篇深入权限系统的核心数据结构与决策逻辑。


一、架构图解:权限系统的四层体系

┌──────────────────────────────────────────────────────┐
│  UI 层                                                │
│  useCanUseTool.tsx / PermissionPrompt.tsx             │
│  → 展示权限请求、收集用户决策                          │
├──────────────────────────────────────────────────────┤
│  决策层                                               │
│  permissions.ts (hasPermissionsToUseTool)             │
│  → 权限检查的主逻辑,14 步决策树的入口                 │
├──────────────────────────────────────────────────────┤
│  中间层(四大子系统)                                  │
│  规则匹配 │ 模式管理 │ AI分类器 │ 路径安全             │
│  shellRuleMatching │ PermMode │ yoloclassifier │ filesystem │
├──────────────────────────────────────────────────────┤
│  基础设施层                                           │
│  设置加载 / 规则解析 / 拒绝追踪 / 沙箱适配             │
└──────────────────────────────────────────────────────┘

自底向上读这张图:基础设施提供配置与状态,四大子系统处理各自专精的判断逻辑,决策层综合所有子系统给出最终结论,UI 层将结论可视化并收集用户输入。


二、核心点拆解

2.1 为什么 AI Agent 的权限比传统应用难得多

Android、Web 同源策略、Unix rwx 权限位——传统应用的权限模型已经很成熟。但 AI Agent 面临三重不确定性,让这些模型失效:

不确定性 传统应用 AI Agent
操作意图 开发者明确知道每步在做什么 LLM 动态决定,可能执行 rm -rf /,可能受 Prompt 注入攻击
操作空间 有限 API 集合(相机/定位/通讯录) Bash 工具的操作空间几乎无限,无法为每种命令预定义权限
用户判断力 权限请求对应直观的功能 python -c 'import base64;exec(base64.b64decode("..."))'——多数用户无法快速判断安全性

结论:Agent 权限系统不能只做"允许/拒绝"的二选一,它需要多层次、多策略、能学习用户偏好的智能决策体系。

2.2 数据结构:权限判决三元组

权限检查的返回值不是简单的布尔值,而是 TypeScript 判别联合类型:

type PermissionDecision =
  | { behavior: 'allow'; updatedInput?; decisionReason? }
  | { behavior: 'ask';   message; suggestions?; decisionReason? }
  | { behavior: 'deny';  message; decisionReason }   // decisionReason 必填

为什么不用简单枚举? 因为每种决策携带的附加信息不同:

  • allow 可以携带 updatedInput——“允许执行,但我帮你修正了输入”(如路径规范化)。允许不总是原样放行,权限层可以在放行的同时变换参数。
  • ask 携带 message(解释为什么需要确认)和可选的 suggestions(建议的规则),让 UI 知道展示什么信息。
  • denydecisionReason必填的,ask 和 allow 是可选的。每一次拒绝都必须解释原因——拒绝比允许需要更多的解释。

决策溯源类型:每个判决都有完整的"决策原因链",记录来源是规则、模式、分类器、安全检查、Hook 还是工作目录限制。这不仅用于 UI 展示,也用于调试(Ctrl+D 可查看完整决策路径)。

特别值得关注的是 safetyCheck 中的 classifierApprovable 布尔字段——它标记了某些安全检查是否可以被 AI 分类器自动处理(true),还是必须由人工确认(false)。这个字段定义了 AI 自主决策的边界。

2.3 四级信任 × 八层规则源:正交的两个维度

四级信任机制

行为 信任级别 语义 典型场景
allow 静默通过 “我信任这个操作” 只读工具、用户白名单命令
ask 人工审批 “我不确定,让人来决定” 文件写入、未知命令
deny 静默拒绝 “绝对不允许” 企业策略禁止的命令
auto AI 分类器决策 “让 AI 帮忙判断” Auto 模式下的动态分类

前三级是确定性的,规则匹配就立即决策。第四级 auto 是 Claude Code 的独特创新——当没有规则明确覆盖时,调用专门的 AI 分类器(YOLO Classifier)做出判断。用 LLM 的语义理解弥补静态规则的覆盖盲区。

八层优先级规则源(高 → 低):

层级 来源 生命周期 谁设置 示例
1 cliArg 单次执行 启动者 --allowed-tools "Bash(git:*)"
2 command 命令执行期 命令作者 斜杠命令 frontmatter 预授权
3 session 当前会话 用户实时 点击"Yes, don’t ask again"
4 flagSettings 动态 系统 Feature flag 关联的权限覆盖
5 policySettings 持久 企业管理员 组织托管策略,禁止执行 curl
6 localSettings 持久 个人 .claude/settings.local.json(gitignored)
7 projectSettings 持久 团队 .claude/settings.json(提交到 Git)
8 userSettings 持久 用户 全局设置,允许 git:*

关键区分规则的来源优先级 VS 行为的检查顺序 是正交的两个维度:

  • 8 层优先级:同类规则(都是 allow)之间谁优先——cliArg > userSettings
  • deny > ask > allow 的检查顺序:不同类别规则之间谁优先

这意味着:即使 session(高优先级)添加了某条 curl 的临时 allow,如果 policySettings 有 curl 的 deny 规则——deny 在 allow 之前被检查,临时允许不会覆盖企业策略的硬底线。

2.4 14 步决策树:权限检查的完整链路

hasPermissionsToUseTool 函数是整个权限系统的主入口,实现了精心排序的 14 步决策树:

hasPermissionsToUseTool(tool, input, context)
│
├─[1a] 工具级 deny 规则?─────────────→ DENY(不可覆盖)
├─[1b] 工具级 ask 规则?──────────────→ ASK(沙箱自动允许例外)
├─[1c] tool.checkPermissions() ───────→ 工具自身细粒度检查
├─[1d] 工具自身拒绝?─────────────────→ DENY
├─[1e] 需要用户交互?─────────────────→ ASK(如 AskUserQuestion)
├─[1f] 内容特定 ask 规则?────────────→ ASK(优先于 bypass 模式)
├─[1g] 安全检查(敏感路径)?─────────→ ASK(免疫 bypass)
│
├─[2a] bypassPermissions 模式?────────→ ALLOW
├─[2b] 工具级 allow 规则?────────────→ ALLOW
│
└─[3]  默认 → ASK
        ├─ dontAsk 模式 → 转为 DENY
        └─ auto 模式 → AI 分类器流程

三个关键设计决策,每一个都有深刻的安全理由:

决策一:deny 永远在 allow 之前。 步骤 1a-1g(否定性检查)全部排在 2a-2b(肯定性检查)之前。即使传入 --allowed-tools "Bash(*)" 最高优先级全量允许规则,只要有任何 deny 规则匹配,操作仍然被拒绝。这是安全设计的"默认拒绝"原则(Default Deny)——先检查所有不应该做的事,确认没有红线后,才检查是否有放行的理由。

决策二:安全检查免疫 bypass 模式。 步骤 1g 的安全检查(对 .git/.claude/ 等敏感路径的保护)在步骤 2a 的 bypassPermissions 检查之前。即使用户选择了"完全信任"模式,对这些关键配置文件的修改仍然需要确认。为什么? 因为 .git/config.claude/settings.json 是权限系统自身的"根基"——如果 Agent 能不经确认地修改这些文件,它就能关闭自己的安全限制,形成"自我提权"攻击。免疫设计切断了这条攻击路径。

决策三:内容特定规则优先于 bypass。 步骤 1f 允许用户配置"某些具体命令总是需要确认"(如 Bash(rm:*) 配置为 ask),这些规则同样免疫 bypass 模式。让用户在"大部分自动化"的同时,对特定高危操作保留人工确认。

2.5 工具自检契约:checkPermissions 的分权设计

步骤 1c 调用了 tool.checkPermissions(input, context)——这是权限系统与工具系统之间的核心契约:

  • BashTool:在这里执行命令注入检测和危险命令模式识别
  • FileEditTool:在这里检查目标路径是否在工作目录内
  • WebFetchTool:在这里验证 URL 是否在允许的域名列表中

分权的好处:通用权限逻辑(deny/ask/allow 规则匹配、模式检查)在 permissions.ts 中集中处理;工具特有的安全判断(这个 Bash 命令是否包含 rm -rf?这个文件路径是否包含符号链接逃逸?)由各工具自行负责。新增工具时,只需实现 checkPermissions 方法即可接入权限系统,不需要修改中心化的权限检查逻辑。这是开闭原则在安全系统中的完美体现。


三、横向对比

维度 Android 权限 Unix rwx Claude Code
权限粒度 API 级别(相机/定位) 文件级别(r/w/x) 操作语义级别(命令/路径/内容)
决策主体 用户(安装时或运行时) 系统内核 用户 + AI 分类器 + 规则引擎
覆盖盲区 新权限类别无法预定义 无法描述操作意图 AI 分类器兜底,但仍有限制
规则继承 App 间隔离,无继承 文件所有者继承 8 层优先级,可被覆盖但有硬底线
可解释性 权限名称(ACCESS_CAMERA) 权限位(rwxr-xr-x) 完整决策原因链 + 规则溯源
绕过防御 Root 可绕过 Root 可绕过 安全检查免疫 bypass,硬编码敏感路径

核心差异:传统权限模型的权限主体是"身份"(这个进程/用户是谁),Claude Code 的权限主体是"操作语义"(这个操作在做什么、风险是什么)。这种从身份到语义的转变,是 AI 系统权限设计的根本创新。


四、实战启示

启示一:判别联合比枚举更能承载语义

allow/ask/deny 不用枚举而用判别联合类型,让每种决策可以携带不同的附加信息。这种设计在任何需要"带上下文的状态"的场景都适用——不要用 status: string,用带 payload 的联合类型。

启示二:把"为什么拒绝"做成必填字段

denydecisionReason 是必填项,allow 是可选项。这个不对称设计强制开发者在拒绝时思考理由,让系统天然可解释。在自己的权限/审计系统中,拒绝事件必须附带原因。

启示三:规则来源优先级 vs 行为优先级——正交设计

这两个维度的正交设计值得反复品味。在任何层级化的规则系统中,“谁的规则优先"和"哪类规则优先"应该独立配置,不要耦合在一起。规则来源决定"同类规则中谁优先”,规则类型决定"不同类规则中谁优先"。

启示四:自我提权攻击——必须在架构层面切断

.git/config.claude/settings.json 这类"元配置"文件必须有独立的保护路径,不能被任何模式(哪怕是 bypass)所覆盖。如果 Agent 能修改自己的权限配置,就能实现"自我提权"。这条攻击路径必须在架构设计时就切断,不能留给运行时检查。

启示五:checkPermissions 契约——开闭原则的安全版

“通用逻辑集中 + 工具特有逻辑分散"的分权设计让权限系统对扩展开放、对修改关闭。每个工具自负其安全责任,中心化的决策树只关注"综合所有意见后该如何决策”。在设计插件/工具系统时,这种安全责任的分权契约应该是标准模式。


五、下期预告

14 步决策树的第 [3] 步是整个权限系统最有趣的部分——当没有任何规则覆盖时,Auto 模式会调用 YOLO Classifier。下一篇将深入:AI 分类器的两阶段设计(64 token 快路径 + 4096 token 推理)、防 Prompt 注入的转录构建策略、断路器模式(连续拒绝 3 次 → 回退人工确认)、六种权限模式的状态机切换、以及渐进式信任 UX 的精妙设计。


思考题:如果企业部署时需要为不同项目配置不同的安全策略,现有的 8 层规则源架构是否足够?假设需要增加一个"项目组级别"的规则层,应该插入在哪一层?会带来哪些权衡?

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐