<!-- title: Claude Code权限与安全沙箱全实战 -->

# Claude Code 权限体系与安全沙箱全实战：从权限配置到Docker隔离的完整防护指南

## 概述

本教程面向需要在团队或生产环境中安全使用 Claude Code 的开发者和安全工程师。你将学会：配置 `settings.json` 的 allow/deny 权限规则、使用 Hooks 拦截危险操作、搭建 Docker 沙箱实现文件系统与网络隔离，最终构建一套多层防御的 Claude Code 安全体系。适合有一定 Claude Code 使用基础、关注安全合规的技术人员。

**适用人群**：中高级开发者、DevOps 工程师、安全工程师、技术团队负责人  
**预计学习时长**：3-4 小时（含动手实践）

---

## 前置条件

| 要求 | 说明 |
|------|------|
| Claude Code CLI | 已安装并完成基本配置（`npm install -g @anthropic-ai/claude-code`） |
| Node.js 18+ | Claude Code 运行环境 |
| Docker（可选） | 第四章沙箱实践需要 |
| Linux/macOS | 本教程命令以 Linux/macOS 为主 |
| 基础 CLI 能力 | 熟悉终端操作和 JSON 编辑 |

---

## 第一章：Claude Code 权限模型深度解析

### 1.1 三级权限控制：Ask / Allow / Deny

Claude Code 的每一次工具调用（Tool Call）——无论是执行 Bash 命令、编辑文件，还是发起网络请求——都必须经过权限系统的审核。这个系统基于三条核心规则运作：

```
┌─────────────────────────────────────────────────┐
│              Claude Code 权限决策树               │
├─────────────────────────────────────────────────┤
│                                                 │
│  工具调用请求                                     │
│       │                                         │
│       ▼                                         │
│  ┌─────────┐   匹配   ┌──────────────────┐      │
│  │ Deny 规则├────────►│ ❌ 直接拒绝（静默）│      │
│  └────┬────┘          └──────────────────┘      │
│       │ 不匹配                                    │
│       ▼                                           │
│  ┌──────────┐  匹配  ┌───────────────────┐       │
│  │ Allow 规则├───────►│ ✅ 自动放行（无提示）│      │
│  └────┬─────┘        └───────────────────┘       │
│       │ 不匹配                                     │
│       ▼                                            │
│  ┌──────────────────────────────┐                 │
│  │ 🟡 弹出确认对话框（Ask 模式）│                 │
│  │ 用户手动选择 Allow / Deny    │                 │
│  └──────────────────────────────┘                 │
│                                                   │
└─────────────────────────────────────────────────┘
```

**关键原则：Deny 优先于 Allow。** 如果一条规则同时匹配 deny 和 allow，deny 始终获胜。这确保了安全策略的绝对权威。

### 1.2 权限配置的层级结构

Claude Code 的配置文件分布在三个层级，形成一套继承与覆盖的体系：

```
~/.claude/settings.json              ← 全局配置（对所有项目生效）
  └── 项目根目录/.claude/settings.json   ← 项目配置（仅对当前项目生效）
       └── settings.local.json          ← 本地配置（不提交到 Git）
```

**优先级规则**：
- `deny` 规则：全局 deny + 项目 deny 取并集，全部生效
- `allow` 规则：项目级 allow 覆盖全局级 allow
- `settings.local.json`：覆盖同目录下的 `settings.json`（用于个人偏好，不进版本控制）

### 1.3 settings.json 完整结构

```json
{
  "permissions": {
    "allow": [
      "Bash(git status)",
      "Bash(git diff *)",
      "Bash(git log *)",
      "Bash(npm test *)",
      "Bash(npm run lint *)",
      "Read",
      "Glob",
      "Grep"
    ],
    "deny": [
      "Bash(rm -rf *)",
      "Bash(curl * | bash *)",
      "Bash(sudo *)",
      "Bash(chmod 777 *)",
      "Edit(*.env*)",
      "Write(*.env*)",
      "Write(*secret*)",
      "Write(*credential*)"
    ]
  }
}
```

**语法解析**：

| 模式 | 含义 | 示例 |
|------|------|------|
| `"Tool"` | 允许该工具的所有调用 | `"Read"` → 可读任意文件 |
| `"Tool(prefix)"` | 匹配以 prefix 开头的参数 | `"Bash(git *)"` → 允许所有 git 命令 |
| `"Tool(*keyword*)"` | 参数包含 keyword | `"Bash(*npm test*)"` |
| `"Tool(path/*)"` | 路径 glob 匹配 | `"Edit(src/**)"` → 只允许编辑 src 目录 |

### 1.4 各工具的权限语法详解

#### Bash 工具

Bash 是最需要严格控制的工具，因为它能执行任意系统命令：

```json
{
  "permissions": {
    "allow": [
      "Bash(git *)",
      "Bash(npm *)",
      "Bash(npx *)",
      "Bash(node *)",
      "Bash(python *)",
      "Bash(ls *)",
      "Bash(cat *)",
      "Bash(echo *)",
      "Bash(mkdir *)",
      "Bash(cp *)",
      "Bash(mv *)"
    ],
    "deny": [
      "Bash(rm -rf /)",
      "Bash(rm -rf ~*)",
      "Bash(sudo *)",
      "Bash(su *)",
      "Bash(chmod 777 *)",
      "Bash(curl * | sh)",
      "Bash(curl * | bash)",
      "Bash(wget * | sh)",
      "Bash(aws s3 rm *)",
      "Bash(docker rm *)",
      "Bash(kubectl delete *)",
      "Bash(pkill *)",
      "Bash(kill -9 *)"
    ]
  }
}
```

#### 文件操作工具（Read / Edit / Write）

```json
{
  "permissions": {
    "allow": [
      "Read",
      "Edit(src/**)",
      "Edit(tests/**)",
      "Write(src/**)",
      "Write(tests/**)"
    ],
    "deny": [
      "Edit(.env*)",
      "Edit(*.pem)",
      "Edit(*.key)",
      "Write(.env*)",
      "Write(*.pem)",
      "Write(*.key)",
      "Write(/etc/*)",
      "Write(/var/*)",
      "Edit(package.json)",
      "Edit(package-lock.json)"
    ]
  }
}
```

#### 网络工具（WebFetch / WebSearch）

```json
{
  "permissions": {
    "allow": [
      "WebFetch",
      "WebSearch"
    ],
    "deny": [
      "WebFetch(http://localhost*)",
      "WebFetch(http://127.0.0.1*)",
      "WebFetch(http://192.168.*)",
      "WebFetch(http://10.*)",
      "WebFetch(http://172.16.*)"
    ]
  }
}
```

> **为什么禁止访问内网地址？** 在 CI/CD 或共享环境中，Claude Code 可能通过 WebFetch 发起 SSRF（Server-Side Request Forgery）攻击，访问内部服务。

### 1.5 通过 CLI 快速配置权限

除了手动编辑 JSON，Claude Code 提供了交互式权限管理：

```bash
# 启动时预设权限
claude --allow "Bash(git *)" --allow "Bash(npm test *)" --deny "Bash(sudo *)"

# 在会话中管理权限
/permissions          # 打开权限管理面板
/permissions allow    # 查看所有 allow 规则
/permissions deny     # 查看所有 deny 规则
```

**常见问题与解决**：

| 问题 | 原因 | 解决方案 |
|------|------|---------|
| 规则不生效 | JSON 语法错误 | 用 `jq . ~/.claude/settings.json` 验证 |
| allow 了还是弹窗 | deny 规则也匹配了 | 检查是否有冲突的 deny 规则 |
| 路径匹配不到 | glob 模式不对 | 使用 `src/**` 而非 `src/*` 递归匹配 |
| 权限太多太乱 | 配置文件膨胀 | 按工具分组，定期清理无用规则 |

---

## 第二章：Hooks——代码级安全守卫

### 2.1 Hooks 是什么？为什么比权限更强？

`settings.json` 的 allow/deny 是静态的字符串匹配，能力有限。Hooks 则允许你在工具调用的生命周期中注入**任意 Shell 脚本逻辑**——你可以检查文件内容、调用外部 API、执行复杂的条件判断，然后决定放行还是拦截。

```mermaid
sequenceDiagram
    participant User as 用户/Claude
    participant HookSystem as Hook 引擎
    participant PreHook as PreToolUse Hook
    participant Tool as 目标工具
    participant PostHook as PostToolUse Hook
    
    User->>HookSystem: 发起工具调用
    HookSystem->>PreHook: 传递工具名+参数(JSON)
    alt PreHook 返回 exit 0
        PreHook->>HookSystem: 放行
        HookSystem->>Tool: 执行工具
        Tool->>HookSystem: 返回结果
        HookSystem->>PostHook: 传递结果(JSON)
        PostHook->>HookSystem: 后处理完成
        HookSystem->>User: 返回最终结果
    else PreHook 返回 exit 2
        PreHook->>HookSystem: 拦截（反馈给 Claude）
        HookSystem->>User: 返回拦截原因
    else PreHook 返回 exit 1 或超时
        PreHook->>HookSystem: 静默放行
        HookSystem->>Tool: 执行工具
    end
```

### 2.2 Hook 事件类型全览

截至 2026 年初，Claude Code 支持以下 Hook 事件：

| 事件 | 触发时机 | 典型用途 |
|------|---------|---------|
| `PreToolUse` | 工具执行**之前** | 拦截危险操作、参数校验 |
| `PostToolUse` | 工具执行**之后** | 自动格式化、日志记录、触发构建 |
| `Notification` | Claude 通知用户时 | 自定义通知渠道（Slack/钉钉） |
| `Stop` | Claude 完成回复时 | 生成报告、触发 CI |
| `SubagentStop` | 子 Agent 完成时 | 聚合子任务结果 |

### 2.3 Hook 配置结构

Hooks 配置在 `settings.json` 的 `hooks` 字段中：

```json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "python3 /path/to/security-guard.py"
          }
        ]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "npx prettier --write $CLAUDE_FILE_PATH 2>/dev/null || true"
          }
        ]
      }
    ]
  }
}
```

**字段说明**：

- `matcher`：正则表达式，匹配工具名。`"Bash"` 精确匹配，`"Edit|Write"` 匹配两者
- `hooks[].type`：目前支持 `"command"`（执行 Shell 命令）
- `hooks[].command`：要执行的命令

### 2.4 Hook 的 JSON 输入格式

Hook 脚本通过 **stdin** 接收 JSON 数据：

```json
{
  "tool_name": "Bash",
  "tool_input": {
    "command": "rm -rf /tmp/test",
    "description": "清理临时文件"
  },
  "session_id": "abc123"
}
```

**PreToolUse 的退出码语义**：

| 退出码 | 含义 | 行为 |
|--------|------|------|
| `0` | 放行 | 工具正常执行 |
| `2` | 拦截 | 阻止执行，stdout 内容作为反馈给 Claude |
| 其他 / 超时 | 忽略 | 工具正常执行（安全失败策略） |

### 2.5 实战：五个生产级安全 Hook

#### Hook 1：危险命令拦截器

```python
#!/usr/bin/env python3
"""danger-guard.py — 拦截危险的 Bash 命令"""
import sys, json

DANGEROUS_PATTERNS = [
    "rm -rf /", "rm -rf ~", "rm -rf /*",
    "sudo rm", ":(){ :|:& };:",  # fork bomb
    "dd if=/dev/zero",
    "mkfs.", "format ",
    "> /dev/sd", "chmod -R 777 /",
    "curl * | bash", "curl * | sh",
    "wget * | bash", "wget * | sh",
]

def check(data):
    if data.get("tool_name") != "Bash":
        sys.exit(0)
    
    cmd = data.get("tool_input", {}).get("command", "")
    
    for pattern in DANGEROUS_PATTERNS:
        # 简单的通配符匹配
        if "*" in pattern:
            parts = pattern.split("*")
            if all(p in cmd for p in parts if p):
                print(f"⛔ 危险命令已被拦截！匹配模式: {pattern}")
                print(f"   命令: {cmd}")
                sys.exit(2)
        elif pattern in cmd:
            print(f"⛔ 危险命令已被拦截！匹配模式: {pattern}")
            print(f"   命令: {cmd}")
            sys.exit(2)
    
    sys.exit(0)  # 放行

data = json.load(sys.stdin)
check(data)
```

配置：
```json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "python3 ~/.claude/hooks/danger-guard.py"
          }
        ]
      }
    ]
  }
}
```

#### Hook 2：敏感文件保护

```python
#!/usr/bin/env python3
"""file-guard.py — 保护敏感文件不被修改或删除"""
import sys, json, re

PROTECTED_PATTERNS = [
    r"\.env($|\.|$)", r"\.env\.",
    r"\.pem$", r"\.key$", r"\.p12$",
    r"credentials", r"secrets?[/\\]",
    r"id_rsa", r"id_ed25519",
    r"\.ssh[/\\]",
    r"\.gnupg[/\\]",
    r"\.aws[/\\]credentials",
]

def check(data):
    tool = data.get("tool_name", "")
    if tool not in ("Edit", "Write", "Bash"):
        sys.exit(0)
    
    if tool == "Bash":
        cmd = data.get("tool_input", {}).get("command", "")
        # 检查是否涉及敏感文件的删除或覆盖
        for p in PROTECTED_PATTERNS:
            if re.search(p, cmd):
                print(f"🔒 操作被阻止：涉及敏感文件/目录 (模式: {p})")
                print(f"   命令: {cmd}")
                sys.exit(2)
        sys.exit(0)
    
    file_path = data.get("tool_input", {}).get("file_path", "")
    for p in PROTECTED_PATTERNS:
        if re.search(p, file_path):
            print(f"🔒 文件被保护，禁止 {tool} 操作: {file_path}")
            sys.exit(2)
    
    sys.exit(0)

data = json.load(sys.stdin)
check(data)
```

#### Hook 3：自动代码格式化

```python
#!/usr/bin/env python3
"""auto-format.py — 文件编辑后自动格式化"""
import sys, json, subprocess, os

def format_file(data):
    tool = data.get("tool_name", "")
    if tool not in ("Edit", "Write"):
        sys.exit(0)
    
    file_path = data.get("tool_input", {}).get("file_path", "")
    if not file_path or not os.path.exists(file_path):
        sys.exit(0)
    
    ext = os.path.splitext(file_path)[1]
    
    # 根据文件类型选择格式化工具
    formatters = {
        ".js": ["npx", "prettier", "--write"],
        ".ts": ["npx", "prettier", "--write"],
        ".jsx": ["npx", "prettier", "--write"],
        ".tsx": ["npx", "prettier", "--write"],
        ".css": ["npx", "prettier", "--write"],
        ".json": ["npx", "prettier", "--write"],
        ".py": ["python3", "-m", "black"],
        ".go": ["gofmt", "-w"],
        ".rs": ["rustfmt"],
    }
    
    formatter = formatters.get(ext)
    if formatter:
        try:
            subprocess.run(
                formatter + [file_path],
                capture_output=True, timeout=10
            )
        except Exception:
            pass  # 格式化失败不影响主流程
    
    sys.exit(0)

data = json.load(sys.stdin)
format_file(data)
```

#### Hook 4：Git 仓库保护

```python
#!/usr/bin/env python3
"""git-guard.py — 防止在 main/master 分支上直接修改"""
import sys, json, subprocess

def check(data):
    if data.get("tool_name") != "Bash":
        sys.exit(0)
    
    cmd = data.get("tool_input", {}).get("command", "")
    
    # 只检查 git commit / git push 操作
    if "git commit" not in cmd and "git push" not in cmd:
        sys.exit(0)
    
    try:
        result = subprocess.run(
            ["git", "rev-parse", "--abbrev-ref", "HEAD"],
            capture_output=True, text=True, timeout=5
        )
        branch = result.stdout.strip()
        
        if branch in ("main", "master"):
            print(f"🛡️ 禁止在 {branch} 分支上直接 commit/push！")
            print(f"   请创建新分支: git checkout -b feature/xxx")
            sys.exit(2)
    except Exception:
        pass
    
    sys.exit(0)

data = json.load(sys.stdin)
check(data)
```

#### Hook 5：操作审计日志

```python
#!/usr/bin/env python3
"""audit-logger.py — 记录所有工具调用到审计日志"""
import sys, json, os
from datetime import datetime

LOG_FILE = os.path.expanduser("~/.claude/audit.log")

def log(data):
    entry = {
        "timestamp": datetime.now().isoformat(),
        "tool": data.get("tool_name"),
        "input_summary": str(data.get("tool_input", {}))[:500],
        "session_id": data.get("session_id", "unknown"),
    }
    
    with open(LOG_FILE, "a") as f:
        f.write(json.dumps(entry, ensure_ascii=False) + "\n")
    
    sys.exit(0)  # 只记录，不拦截

data = json.load(sys.stdin)
log(data)
```

### 2.6 组合所有 Hook 的完整配置

```json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "python3 ~/.claude/hooks/danger-guard.py"
          },
          {
            "type": "command",
            "command": "python3 ~/.claude/hooks/git-guard.py"
          }
        ]
      },
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "python3 ~/.claude/hooks/file-guard.py"
          }
        ]
      },
      {
        "matcher": ".*",
        "hooks": [
          {
            "type": "command",
            "command": "python3 ~/.claude/hooks/audit-logger.py"
          }
        ]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "python3 ~/.claude/hooks/auto-format.py"
          }
        ]
      }
    ]
  }
}
```

> **注意**：同一个 matcher 下可以有多个 Hook，它们按顺序执行。任何一个返回 exit 2 就会拦截。

---

## 第三章：权限与 Hooks 的协同防御

### 3.1 纵深防御架构

权限系统和 Hooks 不是二选一的关系，而是**多层防线**：

```mermaid
flowchart TB
    subgraph "第一层：静态权限防线"
        A[工具调用] --> B{Deny 规则匹配?}
        B -->|是| C[❌ 静默拒绝]
        B -->|否| D{Allow 规则匹配?}
        D -->|是| E[✅ 自动放行]
        D -->|否| F{PreToolUse Hook}
    end

    subgraph "第二层：动态 Hook 防线"
        F -->|exit 2| G[❌ Hook 拦截]
        F -->|exit 0| H{用户确认}
    end

    subgraph "第三层：人工确认"
        H -->|拒绝| I[❌ 用户拒绝]
        H -->|允许| J[执行工具]
    end

    subgraph "第四层：后置处理"
        J --> K[PostToolUse Hook]
        K --> L[日志 / 格式化 / 验证]
    end

    style C fill:#ff6b6b
    style G fill:#ff6b6b
    style I fill:#ff6b6b
    style E fill:#51cf66
    style J fill:#51cf66
    style L fill:#74c0fc
```

### 3.2 配置策略矩阵

不同场景需要不同的安全级别：

| 场景 | 权限策略 | Hook 策略 | 推荐模式 |
|------|---------|----------|---------|
| 个人学习/实验 | 宽松 allow + 少量 deny | 审计日志 | `--auto-accept-edits` |
| 团队项目开发 | 精确 allow + deny 敏感操作 | 全部 5 个 Hook | 标准 Ask 模式 |
| CI/CD 自动化 | 严格 allow 白名单 | 守卫 + 审计 | `--dangerously-skip-permissions` + Docker |
| 安全审计 | 严格 deny + 最小 allow | 全 Hook + 额外验证 | 最严格模式 |

### 3.3 实战：团队项目安全配置模板

创建 `.claude/settings.json`（提交到 Git，团队共享）：

```json
{
  "permissions": {
    "allow": [
      "Read",
      "Glob",
      "Grep",
      "WebSearch",
      "Bash(git status)",
      "Bash(git diff *)",
      "Bash(git log *)",
      "Bash(npm test *)",
      "Bash(npm run lint *)",
      "Bash(npm run build *)",
      "Bash(npm run typecheck *)",
      "Bash(npx *)",
      "Bash(node *)",
      "Bash(ls *)",
      "Bash(cat *)",
      "Bash(head *)",
      "Bash(tail *)",
      "Bash(find *)",
      "Bash(grep *)",
      "Bash(wc *)",
      "Bash(echo *)"
    ],
    "deny": [
      "Bash(rm -rf *)",
      "Bash(sudo *)",
      "Bash(chmod 777 *)",
      "Bash(curl * | sh*)",
      "Bash(curl * | bash*)",
      "Bash(wget * | sh*)",
      "Bash(docker rm *)",
      "Bash(kubectl delete *)",
      "Bash(psql *)",
      "Bash(mysql *)",
      "Bash(mongosh *)",
      "Write(.env*)",
      "Write(*.pem)",
      "Write(*.key)",
      "Write(*.secret*)",
      "Edit(.env*)",
      "Edit(*.pem)",
      "Edit(*.key)",
      "Edit(*.secret*)"
    ]
  },
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "python3 scripts/hooks/danger-guard.py"
          }
        ]
      },
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "python3 scripts/hooks/file-guard.py"
          }
        ]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "python3 scripts/hooks/auto-format.py"
          }
        ]
      }
    ]
  }
}
```

创建 `.claude/settings.local.json`（不提交到 Git，个人覆盖）：

```json
{
  "permissions": {
    "allow": [
      "Bash(docker *)",
      "Bash(kubectl *)",
      "Bash(terraform *)",
      "Bash(aws *)"
    ]
  }
}
```

在 `.gitignore` 中添加：
```
.claude/settings.local.json
```

---

## 第四章：Docker 沙箱——终极隔离方案

### 4.1 为什么需要沙箱？

权限和 Hooks 保护的是**代码层面的操作安全**，但无法防御以下场景：
- Claude Code 进程被利用执行任意代码
- 文件系统被越权访问
- 网络被用来攻击内网服务
- 环境变量中的密钥被读取

Docker 沙箱提供了**操作系统级别的隔离**，即使 Claude Code 被完全控制，攻击者也只能在容器内部活动。

### 4.2 沙箱方案对比

```mermaid
flowchart LR
    subgraph "方案A：内置沙箱"
        A1[Claude Code] --> A2[Seatbelt / Landlock]
        A2 --> A3[受限文件系统]
    end

    subgraph "方案B：Docker 容器"
        B1[Claude Code] --> B2[Docker Container]
        B2 --> B3[命名空间隔离]
        B2 --> B4[网络隔离]
        B2 --> B5[资源限制]
    end

    subgraph "方案C：Dev Container"
        C1[Claude Code] --> C2[VS Code Dev Container]
        C2 --> C3[完整开发环境]
    end

    style A2 fill:#ffd43b
    style B2 fill:#51cf66
    style C2 fill:#74c0fc
```

| 方案 | 隔离级别 | 易用性 | 适用场景 |
|------|---------|--------|---------|
| 内置沙箱（macOS Seatbelt / Linux Landlock） | 中 | ⭐⭐⭐⭐⭐ | 个人开发、macOS 用户 |
| Docker 容器 | 高 | ⭐⭐⭐ | CI/CD、团队共享、Linux 服务器 |
| Dev Container | 高 | ⭐⭐⭐⭐ | VS Code 用户、团队项目 |

### 4.3 实战：从零搭建 Docker 沙箱

#### Step 1：创建 Dockerfile

```dockerfile
# claude-sandbox/Dockerfile
FROM node:20-slim

# 安装基础工具
RUN apt-get update && apt-get install -y \
    git \
    python3 \
    python3-pip \
    curl \
    jq \
    && rm -rf /var/lib/apt/lists/*

# 安装 Claude Code
RUN npm install -g @anthropic-ai/claude-code

# 创建非 root 用户
RUN useradd -m -s /bin/bash claude
USER claude
WORKDIR /home/claude/workspace

# 设置安全的环境变量
ENV NODE_ENV=development
ENV CLAUDE_CODE_SANDBOX=true

ENTRYPOINT ["claude"]
```

#### Step 2：创建 docker-compose.yml

```yaml
# claude-sandbox/docker-compose.yml
version: '3.8'

services:
  claude-sandbox:
    build: .
    container_name: claude-code-sandbox
    # 关键安全配置
    security_opt:
      - no-new-privileges:true
    read_only: false
    # 资源限制
    deploy:
      resources:
        limits:
          cpus: '2.0'
          memory: 4G
        reservations:
          cpus: '0.5'
          memory: 512M
    # 网络隔离（仅 DNS，无外网）
    networks:
      - claude-net
    # 文件系统挂载（只挂载项目目录）
    volumes:
      - ../:/home/claude/workspace:rw
      - claude-home:/home/claude/.claude
    # 环境变量（从 .env 传入 API Key）
    environment:
      - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
    # 禁止特权升级
    cap_drop:
      - ALL
    stdin_open: true
    tty: true

networks:
  claude-net:
    driver: bridge
    internal: false  # 设为 true 可完全禁止外网

volumes:
  claude-home:
```

#### Step 3：创建安全配置

```json
{
  "permissions": {
    "allow": [
      "Read",
      "Glob",
      "Grep",
      "Bash(git *)",
      "Bash(npm *)",
      "Bash(npx *)",
      "Bash(node *)",
      "Bash(python3 *)",
      "Bash(ls *)",
      "Bash(cat *)",
      "Bash(find *)",
      "Bash(echo *)",
      "Bash(mkdir *)",
      "Bash(test *)",
      "Edit(src/**)",
      "Edit(tests/**)",
      "Write(src/**)",
      "Write(tests/**)"
    ],
    "deny": [
      "Bash(sudo *)",
      "Bash(su *)",
      "Bash(rm -rf /)",
      "Bash(curl * | *)",
      "Bash(wget * | *)",
      "Bash(apt *)",
      "Bash(yum *)",
      "Bash(pip install *)",
      "Bash(npm install -g *)",
      "Write(*)",
      "Edit(*)"
    ]
  }
}
```

#### Step 4：启动和管理沙箱

```bash
# 构建镜像
cd claude-sandbox
docker compose build

# 交互式启动（连接到终端）
docker compose run --rm claude-sandbox

# 启动时传入项目特定的权限配置
docker compose run --rm \
  -v $(pwd)/sandbox-settings.json:/home/claude/.claude/settings.json:ro \
  claude-sandbox

# 以 -p 模式执行任务（非交互式）
docker compose run --rm claude-sandbox \
  -p "分析 src/ 目录的代码质量，给出改进建议"

# 执行完成后自动销毁容器
docker compose down
```

#### Step 5：网络隔离配置（可选但推荐）

如果需要禁止 Claude Code 访问外网，但允许访问特定 API：

```yaml
# 在 docker-compose.yml 中替换 networks 配置
networks:
  claude-net:
    driver: bridge
    internal: true  # 完全禁止外网访问
    # 需要额外配置 DNS 和 API 代理
```

如果需要允许访问 Anthropic API 但禁止其他外网：

```yaml
services:
  claude-sandbox:
    networks:
      - claude-net
    dns:
      - 8.8.8.8  # 允许 DNS 解析

  api-proxy:
    image: nginx:alpine
    networks:
      - claude-net
      - external-net
    # 配置 nginx 仅代理 api.anthropic.com

networks:
  claude-net:
    internal: true
  external-net:
    driver: bridge
```

### 4.4 无 Docker 的轻量替代：内置沙箱模式

在不方便使用 Docker 的环境（如 macOS），可以使用 Claude Code 内置的沙箱：

```bash
# macOS：使用 Seatbelt 沙箱
claude --sandbox

# 或在 settings.json 中配置
# macOS 会自动使用 Seatbelt
# Linux 会使用 Landlock LSM
```

内置沙箱的限制：
- macOS Seatbelt：限制文件系统访问、禁止网络（可配置）
- Linux Landlock：限制文件系统访问（需要内核 5.13+）
- 不如 Docker 隔离彻底，但零配置即用

---

## 第五章：完整实战项目——安全加固的 Claude Code 开发环境

### 5.1 项目目标

为一个 5 人前端团队搭建 Claude Code 安全开发环境，要求：
1. 团队成员共享安全策略
2. 个人可自定义覆盖
3. CI/CD 中可无人值守运行
4. 敏感文件绝对保护
5. 所有操作可审计

### 5.2 项目结构

```
my-project/
├── .claude/
│   ├── settings.json          # 团队共享安全策略（提交 Git）
│   ├── hooks/
│   │   ├── danger-guard.py    # 危险命令拦截
│   │   ├── file-guard.py      # 敏感文件保护
│   │   ├── git-guard.py       # Git 分支保护
│   │   ├── auto-format.py     # 自动格式化
│   │   └── audit-logger.py    # 审计日志
│   └── audit/                 # 审计日志存储（gitignore）
│       └── .gitkeep
├── .claude-sandbox/           # Docker 沙箱配置
│   ├── Dockerfile
│   ├── docker-compose.yml
│   └── sandbox-settings.json  # 沙箱内的权限配置
├── .github/
│   └── workflows/
│       └── claude-review.yml  # CI 中使用 Claude Code
├── CLAUDE.md                  # 项目指令文件
├── .gitignore
├── package.json
└── src/
```

### 5.3 完整的 CLAUDE.md 配置

```markdown
# Project: MyProject

## Tech Stack
- React 18 + TypeScript
- Vite
- TailwindCSS
- Vitest + React Testing Library

## Architecture
- src/components/ — UI 组件
- src/hooks/ — 自定义 React Hooks
- src/services/ — API 调用层
- src/utils/ — 工具函数
- tests/ — 测试文件

## Rules
- 所有新代码必须包含对应测试
- 使用 TypeScript strict mode
- 组件使用函数式组件 + Hooks
- 不要修改 package.json 中的依赖版本
- 不要删除 .env.example 中的变量

## Commands
- 构建: npm run build
- 测试: npm run test
- Lint: npm run lint
- 类型检查: npm run typecheck
```

### 5.4 CI/CD 集成：GitHub Actions 安全配置

```yaml
# .github/workflows/claude-review.yml
name: Claude Code Review

on:
  pull_request:
    types: [opened, synchronize]

jobs:
  claude-review:
    runs-on: ubuntu-latest
    container:
      image: node:20-slim
      options: --user root
    
    steps:
      - uses: actions/checkout@v4
      
      - name: Install dependencies
        run: |
          npm ci
          npm install -g @anthropic-ai/claude-code
      
      - name: Run Claude Code Review
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
        run: |
          claude -p "Review the changes in this PR for:
          1. Security vulnerabilities
          2. Code quality issues
          3. Missing tests
          4. Breaking changes
          
          Be specific and cite file paths." \
            --allowedTools "Read,Glob,Grep,Bash(git diff *)" \
            --max-turns 10
```

**关键安全措施**：
- 使用 `--allowedTools` 限制可用工具为只读
- `--max-turns` 防止无限循环
- API Key 存储在 GitHub Secrets 中
- 容器隔离运行

### 5.5 验证安全配置

创建一个验证脚本：

```bash
#!/bin/bash
# scripts/verify-security.sh — 验证 Claude Code 安全配置

set -e

echo "🔍 验证 Claude Code 安全配置..."
echo ""

# 1. 检查 settings.json 是否存在且语法正确
echo "✅ 检查 settings.json..."
if [ -f ".claude/settings.json" ]; then
    jq empty .claude/settings.json 2>/dev/null && echo "  JSON 语法正确" || echo "  ❌ JSON 语法错误！"
else
    echo "  ❌ .claude/settings.json 不存在！"
fi

# 2. 检查 deny 规则是否覆盖关键危险操作
echo ""
echo "✅ 检查 deny 规则覆盖..."
DENOULEMENTS=("rm -rf" "sudo" "chmod 777" "curl.*bash")
for pattern in "${DENOULEMENTS[@]}"; do
    if grep -q "$pattern" .claude/settings.json 2>/dev/null; then
        echo "  ✓ $pattern 已被 deny"
    else
        echo "  ⚠ $pattern 未被 deny"
    fi
done

# 3. 检查 Hook 脚本是否存在且可执行
echo ""
echo "✅ 检查 Hook 脚本..."
for hook in danger-guard file-guard git-guard auto-format audit-logger; do
    if [ -f ".claude/hooks/${hook}.py" ]; then
        echo "  ✓ ${hook}.py 存在"
        python3 -m py_compile ".claude/hooks/${hook}.py" 2>/dev/null && echo "    语法正确" || echo "    ❌ 语法错误"
    else
        echo "  ⚠ ${hook}.py 不存在"
    fi
done

# 4. 检查 Docker 沙箱配置
echo ""
echo "✅ 检查 Docker 沙箱..."
if [ -f ".claude-sandbox/Dockerfile" ]; then
    echo "  ✓ Dockerfile 存在"
    if grep -q "cap_drop" .claude-sandbox/docker-compose.yml 2>/dev/null; then
        echo "  ✓ 已配置 cap_drop"
    else
        echo "  ⚠ 未配置 cap_drop"
    fi
    if grep -q "no-new-privileges" .claude-sandbox/docker-compose.yml 2>/dev/null; then
        echo "  ✓ 已配置 no-new-privileges"
    else
        echo "  ⚠ 未配置 no-new-privileges"
    fi
else
    echo "  ⚠ Docker 沙箱未配置"
fi

# 5. 检查 .gitignore 是否排除了敏感文件
echo ""
echo "✅ 检查 .gitignore..."
for item in "settings.local.json" ".env"; do
    if grep -q "$item" .gitignore 2>/dev/null; then
        echo "  ✓ $item 已被 gitignore"
    else
        echo "  ⚠ $item 未被 gitignore"
    fi
done

echo ""
echo "🎉 安全配置验证完成！"
```

运行验证：
```bash
chmod +x scripts/verify-security.sh
./scripts/verify-security.sh
```

---

## 第六章：安全事件响应与故障排查

### 6.1 常见安全问题排查

| 问题现象 | 可能原因 | 排查命令 | 解决方案 |
|---------|---------|---------|---------|
| Hook 不触发 | 脚本不可执行或路径错误 | `ls -la .claude/hooks/` | `chmod +x .claude/hooks/*.py` |
| 所有操作被拦截 | Hook 脚本有 Bug | 检查审计日志 | `python3 .claude/hooks/danger-guard.py <<< '{"tool_name":"Read","tool_input":{}}'` |
| Docker 容器启动失败 | 权限不足 | `docker compose logs` | 确保用户在 docker 组 |
| API Key 泄露 | settings.json 包含密钥 | `git log --all --full-history -- '*.env'` | 使用 Git history 重写 |
| Claude Code 异常慢 | Docker 资源不足 | `docker stats` | 增大内存/CPU 限制 |

### 6.2 审计日志分析

```bash
# 查看今天的审计日志
cat ~/.claude/audit.log | jq -c 'select(.timestamp | startswith("2026-06-11"))'

# 统计各工具调用次数
cat ~/.claude/audit.log | jq -r '.tool' | sort | uniq -c | sort -rn

# 查找涉及敏感文件的操作
cat ~/.claude/audit.log | jq -c 'select(.input_summary | test("\\.env|\\.pem|\\.key|secret"))'

# 查看特定会话的所有操作
cat ~/.claude/audit.log | jq -c 'select(.session_id == "abc123")'
```

### 6.3 安全清单（Security Checklist）

在生产环境部署 Claude Code 前，逐项确认：

```
□ settings.json 配置了 deny 规则覆盖 rm -rf、sudo、curl|bash
□ 敏感文件 (.env, .pem, .key) 被 deny 保护
□ PreToolUse Hook 已部署并测试
□ 审计日志已启用
□ API Key 不在代码仓库中
□ settings.local.json 在 .gitignore 中
□ Docker 沙箱已配置资源限制
□ Docker 容器使用非 root 用户
□ Docker 已配置 cap_drop: ALL
□ 网络策略已按需配置（internal: true 或 API 代理）
□ CI/CD 中 Claude Code 使用只读工具
□ 定期审查审计日志
```

---

## 第七章：进阶主题

### 7.1 Managed Settings（企业级策略下发）

企业团队可以通过 Anthropic 的管理后台（Anthropic Console）下发**不可覆盖的安全策略**，确保即使开发者修改本地 settings.json 也无法绕过：

```json
{
  "managedSettings": {
    "permissions": {
      "deny": [
        "Bash(sudo *)",
        "Bash(rm -rf *)",
        "Bash(curl * | *)",
        "Write(.env*)",
        "Write(*.pem)"
      ]
    }
  }
}
```

Managed settings 的优先级高于所有本地配置，且用户无法修改。

### 7.2 多环境配置策略

```bash
# 开发环境：宽松
claude --settings .claude/settings.dev.json

# 测试环境：标准
claude --settings .claude/settings.test.json

# 生产环境：严格
claude --settings .claude/settings.prod.json
```

或使用环境变量驱动：

```python
#!/usr/bin/env python3
"""env-settings.py — 根据环境变量选择配置"""
import os, json, shutil

env = os.getenv("CLAUDE_ENV", "dev")
settings_files = {
    "dev": "settings.dev.json",
    "staging": "settings.staging.json",
    "prod": "settings.prod.json",
}

src = f".claude/profiles/{settings_files[env]}"
dst = ".claude/settings.json"
shutil.copy2(src, dst)
print(f"已切换到 {env} 环境配置")
```

### 7.3 与 IDE 安全集成

VS Code 和 JetBrains 的 Claude Code 插件会读取同一套 `settings.json` 配置。确保：
- IDE 插件版本与 CLI 版本一致
- IDE 的 workspace settings 不覆盖安全策略
- 在 IDE 中也启用审计日志

---

## 延伸阅读

- [Anthropic 官方 Hooks 文档](https://code.claude.com/docs/en/hooks) — Hook 事件的完整参考手册
- [Anthropic 权限配置指南](https://code.claude.com/docs/en/permissions) — 权限系统的官方说明
- [Anthropic 沙箱环境文档](https://code.claude.com/docs/en/sandbox-environments) — 官方沙箱方案对比
- [Claude Code Hooks Complete Guide (2026)](https://aiorg.dev/blog/claude-code-hooks) — 20+ 即用型 Hook 配置示例
- [Docker Sandboxes for Coding Agents](https://www.docker.com/blog/docker-sandboxes-run-claude-code-and-other-coding-agents-unsupervised-but-safely/) — Docker 官方的 AI Agent 沙箱指南
- [Claude Code Permissions Deep Dive](https://allahabadi.dev/blogs/ai/claude-code-permissions-settings-explained/) — 权限语法全面解析

## 训练营适用性评估

| 评估维度 | 说明 |
|---------|------|
| 适合训练营类型 | 企业内训（AI 安全专题）、高级开发者训练营、DevOps 安全培训 |
| 学员基础要求 | 已完成 Claude Code 入门 + 至少一个实战项目 |
| 预计教学时长 | 3-4 小时（讲解 1.5h + 动手实践 1.5h + 讨论 1h） |
| 实验环境要求 | 每人一台 Linux/macOS 机器 + Docker 环境 |
| 核心产出 | 学员带走一套完整的安全配置模板 + 5 个 Hook 脚本 + Docker 沙箱配置 |

## 参考来源

1. [Automate actions with hooks - Claude Code Docs](https://code.claude.com/docs/en/hooks-guide) — Anthropic 官方 Hooks 使用指南，涵盖 PreToolUse、PostToolUse 等生命周期事件配置
2. [Configure permissions - Claude Code Docs](https://code.claude.com/docs/en/permissions) — Anthropic 官方权限配置文档，详细说明 allow/deny 语法和层级结构
3. [Choose a sandbox environment - Claude Code Docs](https://code.claude.com/docs/en/sandbox-environments) — Anthropic 官方沙箱方案对比，覆盖内置沙箱、Docker、Dev Container
4. [Claude Code Hooks: Complete Guide with 20+ Examples (2026)](https://aiorg.dev/blog/claude-code-hooks) — 社区维护的 Hooks 完整指南，提供生产级配置示例
5. [Docker Sandboxes: Run Claude Code Safely](https://www.docker.com/blog/docker-sandboxes-run-claude-code-and-other-coding-agents-unsupervised-but-safely/) — Docker 官方博客，详解如何用 microVM 和容器隔离安全运行 AI 编程 Agent

> [!tip] 51学通信知识星球
> **星主：爱卫生**（微信：gprshome201101）——公众号「51学通信」创办者，19 年通信行业运维与讲师经验，著有《GPRS网络信令实例详解》《EPC原理与实践》《5G核心网原理与实践》三本纸质书（各大电商平台有售）。
> **星球定位**：深耕 5G 核心网、IMS、NFV/AI、云原生等 ICT 领域，主打运维岗位与信令分析。
> **当前规模**：5200 篇主题 / 990 个回答，198 元/年。
> **加入福利**：加入星球后请加爱卫生微信，拉您进知识星球年度陪伴与答疑群——不限量回复您的各种问题，另有群内分享。
> **AI 加持**：51学通信知识星球已作为 skill 接入 WorkBuddy，使用 deepseek-4-flash 在海量星球帖子中精准找贴、找视频、找 FAQ 和案例，做总结、找文档和 PPT 等场景全覆盖。

![51学通信知识星球海报-扫码加入](https://wiki.500nian.com/images/zhixingqiu_qrcode.png)
