Skip to content

08 — 权限与安全

概述

权限系统是 Claude Code 最重要的安全机制。它的设计原则是:AI 的所有写操作都必须经过用户授权。但在不同场景下,"授权"的含义不同——手动确认每个操作太慢,全自动又不安全。因此系统提供了多级权限模式多源决策机制来平衡安全性和效率。

权限检查全流程

当模型调用一个 Tool 时,权限系统按以下顺序执行检查:

权限模式

模式行为适用场景
default只读自动允许,写操作检查规则日常使用(默认)
plan大部分写操作需确认需要谨慎审查时
auto大部分操作自动允许(基于 ML 分类器)信任模型、追求效率
bypassPermissions所有操作自动允许完全信任(需明确 opt-in)

模式存储在 AppState.toolPermissionContext.mode 中,用户可通过 /permissions 切换。

权限规则 (ToolPermissionContext)

除了模式,还有精细的 规则集 控制单个工具的行为:

typescript
type ToolPermissionContext = {
  mode: PermissionMode
  alwaysAllowRules: ToolPermissionRulesBySource   // 始终允许
  alwaysDenyRules: ToolPermissionRulesBySource     // 始终拒绝
  alwaysAskRules: ToolPermissionRulesBySource      // 始终询问
  // ...
}

规则来自多个来源(按优先级从高到低):

  1. MDM 受管设置 — 企业管理员强制下发
  2. 远程受管设置 — 通过 API 下发
  3. 用户全局设置~/.claude/settings.json
  4. 项目设置.claude/settings.json
  5. 运行时授权 — 用户在弹窗中选择"Always allow"

四方竞速决策 — 核心创新

当权限结果是 ask(需要确认)时,系统 同时启动四个决策源,第一个返回结果的胜出。这是一个 "race" 模式,通过原子性的 claim() 函数确保只有一个决策生效。

为什么是竞速而不是串行?

  • 用户在终端: 弹窗出现,用户按 y/n 确认
  • 用户在 IDE: 同时在 VS Code 侧边栏看到权限请求,可以直接点击按钮
  • 自动化场景: Hook 脚本自动判断是否安全(如检查命令是否在白名单中)
  • ML 分类器: 对 Bash 命令进行自动安全评估

这四种来源可能同时活跃,用户可以从任何一个入口响应。竞速模式确保最快的响应立即生效,不会互相阻塞。

claim() 原子操作

typescript
const { resolve: resolveOnce, isResolved, claim } = createResolveOnce(resolve)

// 在每个决策回调中:
onAllow: async () => {
  if (!claim()) return  // 已经有人先响应了,忽略
  resolveOnce({ decision: 'accept', source: 'user' })
}

claim() 返回 true 表示"我是第一个响应的",返回 false 表示"已经有其他人先响应了"。这保证了即使四个源同时返回,也不会出现重复决策。

ML 分类器 (Bash 专用)

分类器特别处理:

  1. 收到 Bash 命令后,在后台启动分类
  2. 如果 200ms 内 用户没有交互,分类器结果可以自动生效
  3. 如果分类器批准,显示 ✓ 标记 1-3 秒后自动消失
  4. 如果分类器拒绝,更新 UI 但用户仍可手动覆盖

200ms 的 "grace period" 是为了避免用户正在输入时被分类器的自动决策打断。

BashTool 安全层

BashTool 是最高风险的工具,因此有 独立于通用权限系统的多层安全检查

每一层都可以独立拒绝命令,提供不同粒度的安全保护。

沙箱 (utils/sandbox/)

macOS 上使用 sandbox-exec (Seatbelt) 隔离不可信命令:

限制说明
文件系统只允许访问工作目录及其子目录
网络限制网络访问(可配置)
进程限制子进程创建
系统调用禁止危险系统调用

沙箱的启用条件由 shouldUseSandbox.ts 判断,通常对未明确授权的 Bash 命令启用。

用户 Hooks (utils/hooks/)

Hooks 允许用户在工具执行前后运行自定义 Shell 脚本。这是一种 外挂式安全检查 机制。

配置格式

settings.json 中配置:

json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "command": "python3 ~/scripts/check-bash-safety.py"
      }
    ],
    "PostToolUse": [
      {
        "matcher": "FileWrite",
        "command": "prettier --write $CLAUDE_FILE_PATH"
      }
    ]
  }
}

Hook 事件类型

事件触发时机可以做什么
PreToolUse工具执行前阻止执行 / 修改输入
PostToolUse工具执行后格式化文件 / 注入上下文
SessionStart会话开始时初始化环境
SessionEnd会话结束时清理资源
Notification收到通知时自定义通知

Hook 执行模型

Hook 可以阻止工具执行:如果 Hook 脚本以退出码 2 退出,并在 stdout 输出 {"decision": "block"},工具调用会被阻止,模型会收到阻止原因。

权限持久化

当用户在弹窗中选择 "Always allow for this tool" 时,规则会被写入 ~/.claude/settings.json,下次会话自动恢复。持久化通过 onChangeAppState.ts 的状态变更监听实现。

拒绝追踪 (denialTracking.ts): 记录用户最近拒绝过的操作,避免在同一会话中反复弹出相同的权限请求。

权限相关文件索引

逻辑层

文件说明
utils/permissions/PermissionMode.ts模式定义
utils/permissions/denialTracking.ts拒绝追踪
hooks/toolPermission/PermissionContext.ts权限上下文
hooks/toolPermission/permissionLogging.ts权限日志
hooks/toolPermission/handlers/interactiveHandler.ts交互式处理(四方竞速核心实现)
hooks/toolPermission/handlers/coordinatorHandler.tsCoordinator 模式处理
hooks/toolPermission/handlers/swarmWorkerHandler.tsSwarm Worker 处理
hooks/useCanUseTool.tsxcanUseTool() Hook 主入口

UI 层

文件说明
components/permissions/PermissionRequest.tsx权限弹窗框架
components/permissions/BashPermissionRequest/Bash 专用审批
components/permissions/FileEditPermissionRequest/文件编辑 Diff + 审批
components/permissions/FileWritePermissionRequest/文件写入审批
components/permissions/WebFetchPermissionRequest/网络请求审批

Bash 安全层

文件说明
tools/BashTool/bashSecurity.ts注入检测
tools/BashTool/bashPermissions.ts权限判断
tools/BashTool/commandSemantics.ts语义分析
tools/BashTool/destructiveCommandWarning.ts危险检测
tools/BashTool/pathValidation.ts路径校验
tools/BashTool/shouldUseSandbox.ts沙箱决策