Skip to content

Latest commit

 

History

History
191 lines (145 loc) · 5.16 KB

File metadata and controls

191 lines (145 loc) · 5.16 KB

05 - 权限系统

权限系统是 Claude Code 的安全核心,每次 Tool 调用都会经过权限检查。


权限模式 (PermissionMode)

模式 行为
default 写操作需要用户确认
plan 只允许只读操作,写操作被拒绝
bypassPermissions 跳过所有权限检查(危险)
auto 自动批准,但经过安全分类器检查
acceptEdits 自动批准编辑,其他操作照常
dontAsk 不弹出确认,直接拒绝需要确认的操作

权限检查流程

Tool 被调用
  │
  ▼
1. validateInput()
   - 校验输入参数合法性
   - 与权限无关,纯数据校验
   - 失败 → 直接返回错误
  │
  ▼
2. 全局拒绝规则检查 (alwaysDenyRules)
   - 匹配 → 直接拒绝,不执行
  │
  ▼
3. checkPermissions() — Tool 级别
   - 每个 Tool 自己的权限逻辑
   - 返回: allow / deny / ask
  │
  ▼
4. 全局允许规则检查 (alwaysAllowRules)
   - 匹配 → 自动批准
  │
  ▼
5. 权限模式检查
   - bypassPermissions → 批准
   - plan 模式 + 写操作 → 拒绝
   - auto 模式 → 安全分类器检查
  │
  ▼
6. 用户确认 (ask)
   - 弹出权限对话框
   - 用户选择: Allow / Deny / Always Allow

ToolPermissionContext

权限上下文定义了当前的权限规则集合:

type ToolPermissionContext = DeepImmutable<{
  mode: PermissionMode
  additionalWorkingDirectories: Map<string, AdditionalWorkingDirectory>
  alwaysAllowRules: ToolPermissionRulesBySource   // 始终允许
  alwaysDenyRules: ToolPermissionRulesBySource     // 始终拒绝
  alwaysAskRules: ToolPermissionRulesBySource      // 始终询问
  isBypassPermissionsModeAvailable: boolean
  strippedDangerousRules?: ToolPermissionRulesBySource  // 被剥离的危险规则
  shouldAvoidPermissionPrompts?: boolean  // 后台 Agent 不能弹出 UI
  awaitAutomatedChecksBeforeDialog?: boolean
  prePlanMode?: PermissionMode  // Plan 模式前的权限模式
}>

注意 DeepImmutable:权限上下文是深度不可变的。Tool 不能修改权限上下文,只能通过 contextModifier 返回新的上下文。


权限规则示例

权限规则按来源组织 (ToolPermissionRulesBySource),来源包括:

  • userSettings — 用户配置 (settings.json)
  • projectSettings — 项目配置 (.claude/settings.json)
  • localSettings — 本地配置 (.claude/settings.local.json)
  • flagSettings — 特性标志下发的配置
  • policySettings — 组织策略
  • cliArg — CLI 参数传入
  • command — 斜杠命令设置
  • session — 用户运行时选择 ("Always Allow")

规则格式:

Tool名称(模式)

例如:

  • Bash(git *) — 允许以 git 开头的 Bash 命令
  • FileEdit(/src/**) — 允许编辑 /src/ 下的文件
  • Bash — 允许所有 Bash 命令(无模式 = 全局拒绝/允许)

preparePermissionMatcher

Tool 可以实现 preparePermissionMatcher() 来支持模式匹配:

// BashTool 的例子:将 "git *" 匹配到 "git status"
preparePermissionMatcher(input) {
  return async (pattern: string) => {
    // 解析 input.command,与 pattern 做 glob 匹配
    return matchesPattern(input.command, pattern)
  }
}

这允许用户创建细粒度规则,如"允许 git 命令但拒绝 rm"。


安全设计原则

1. 失败关闭 (Fail-Closed)

// 默认值:假设不安全
isConcurrencySafe() { return false }  // 默认不并发
isReadOnly() { return false }          // 默认假设有写入
isDestructive() { return false }       // 需要显式声明

Tool 必须主动声明自己是安全的,而不是默认安全。

2. 后台 Agent 不弹 UI

shouldAvoidPermissionPrompts?: boolean

当设为 true(如后台子 Agent),权限提示会被自动拒绝而不是弹出确认框。

3. 拒绝追踪

localDenialTracking?: DenialTrackingState

追踪连续拒绝次数。如果同一操作被连续拒绝多次,会触发降级行为,避免模型陷入无效重试循环。

4. 文件系统安全

  • UNC 路径处理:延迟解析直到权限授予,防止 NTLM 凭证泄露
  • 设备文件阻止:禁止读取 /dev/zero/dev/stdin 等设备文件
  • 二进制文件检测:自动跳过二进制文件(PDF/图片除外)
  • 文件大小限制:编辑操作最大 1 GiB

Tool 过滤

在 Tool 列表提供给模型之前,会经过过滤:

export function filterToolsByDenyRules(
  tools: readonly Tool[],
  permissionContext: ToolPermissionContext
): Tool[] {
  return tools.filter(tool => !getDenyRuleForTool(permissionContext, tool))
}

被全局拒绝的 Tool 不会出现在模型的可用工具列表中——模型根本不知道它们的存在。


权限与 Hooks 的关系

用户可以通过 Hooks 系统定义 PreToolUsePostToolUse 钩子来自定义权限行为:

PreToolUse Hook → 可以 approve/deny/modify 输入
  ↓
内置权限检查 (checkPermissions)
  ↓
PostToolUse Hook → 可以在执行后审计

Hooks 在 [[11 - 配置与内存系统]] 中详细介绍。