AI Native 手册
护栏与安全

密钥与配置:别让工具覆盖你的设置

密钥只放环境变量或钥匙串,配置切换工具可能整份重写你的设置

亲历小工具产品组织阶段 · 通用更新于 2026-10-16

密钥只放两个地方:环境变量(本地是不进 git 的 .env,线上是部署平台的环境变量)和系统钥匙串。不要写进代码、CLAUDE.md、settings.json,或任何会被同步、备份、复制的配置文件。另外要防两件容易忽略的事:配置切换工具可能整份重写你的 ~/.claude/settings.json;各种备份文件里,常常躺着明文密钥。

密钥放哪

场景放哪
项目运行时用的密钥(数据库、第三方 API).env,第一天就加进 .gitignore;线上用部署平台的环境变量
本机命令行工具的 tokenmacOS 钥匙串,用的时候再取
MCP 服务的凭证优先用 OAuth,在 /mcp 里授权;必须用 token 时,在项目的 .mcp.json 里写 ${API_KEY},引用环境变量
CI代码托管平台的 secrets

注意 claude mcp add 的 -H "Authorization: Bearer ..." 和 -e KEY=...:它们会把值明文写进 ~/.claude.json,用户级和本地级的 MCP 配置都存在这个文件里(见官方文档)。

macOS 钥匙串:security 命令

# 存入。-w 放在最后,会提示你输入,密钥不会留在 shell 历史里
security add-generic-password -a "$USER" -s cloudflare-api-token -w

# 更新已有的条目:加 -U
security add-generic-password -U -a "$USER" -s cloudflare-api-token -w

# 取出:只输出密钥本身
security find-generic-password -a "$USER" -s cloudflare-api-token -w

# 删除
security delete-generic-password -a "$USER" -s cloudflare-api-token

用的时候只在那一条命令里取,不要导出成全局环境变量:

CLOUDFLARE_API_TOKEN="$(security find-generic-password -a "$USER" -s cloudflare-api-token -w)" wrangler deploy

别让 agent 把密钥打印出来

Claude 运行命令的输出会进对话记录,而对话记录以 jsonl 文件保存在 ~/.claude/projects/ 下。让它单独执行一次 security find-generic-password ... -w,密钥就留在了对话记录里。只在 $(...) 里取用;更稳的做法是给这条命令加一条 ask 规则 Bash(security find-generic-password *)。ask 规则对 $(...) 里的子命令同样生效,Claude 每次要取密钥都得你点头。

配置切换工具会整份覆盖设置

我用一个模型供应商切换工具(CC Switch 这类)从第三方模型切回官方时,它把 ~/.claude/settings.json 整份重写了:权限规则、hook、插件启用状态全部丢失。表面症状只是“所有插件都关了”,过了很久我才意识到,护栏也跟着没了(见切换工具会整份覆盖设置)。

公平地说,CC Switch 现在的文档(截至 2026-10)写的是:切换时只改连接相关的字段,权限、hook、插件启用状态都不动。但这类工具的合并逻辑会随版本变化,也可能有 bug。规则不变:切换之后检查一遍。

# 切换后,看权限、hook、插件还在不在
jq '{deny: .permissions.deny, hooks: (.hooks // {} | keys), plugins: .enabledPlugins}' ~/.claude/settings.json

更彻底的做法有两个:

  • 试用中 关键的 deny 规则和体检 hook 放进托管设置。切换工具只写用户级文件,碰不到它(写法见权限规则)
  • 业界做法 不让工具改 settings.json。Claude Code 也从环境变量读 ANTHROPIC_BASE_URL 和 ANTHROPIC_AUTH_TOKEN,可以给每个供应商写一个 shell 函数,token 放钥匙串,启动时临时注入。前提是 settings.json 的 env 里没有残留的同名变量
# 放进 ~/.zshrc;地址换成供应商给你的
claude-alt() {
  ANTHROPIC_BASE_URL="https://api.example.com" \
  ANTHROPIC_AUTH_TOKEN="$(security find-generic-password -a "$USER" -s alt-provider-token -w)" \
  claude "$@"
}

备份文件里也可能留着明文密钥

密钥常常藏在你想不到的地方:

  • ~/.claude/settings.json 的 env:供应商切换工具会把第三方的 key 明文写在这里
  • 这个文件的各种副本:你手动备份的 settings.json.bak,以及切换工具自己的备份。据 CC Switch 的文档,它第一次改写配置前会备份原文件,数据库和备份都放在 ~/.cc-switch/ 下
  • ~/.claude.json:用 -H、-e 添加的 MCP 凭证。Claude Code 每次写这个文件之前,会在 ~/.claude/backups/ 里留一份备份,保留最近 5 份
  • 对话记录:~/.claude/projects/ 下的 jsonl,前提是密钥曾经被打印出来
  • shell 历史:直接敲过的 export TOKEN=...,或者把密钥写在 -w 后面的命令

查一下哪些文件里有疑似密钥的字段。-l 只列文件名,不会把内容打印出来:

grep -rlE 'TOKEN|API_KEY|SECRET|PASSWORD' ~/.claude/settings.json ~/.claude.json ~/.claude/backups ~/.cc-switch 2>/dev/null

找到之后,先轮换密钥,再删文件。密钥一旦落进备份、同步盘或别人可能看到的地方,删掉文件也收不回来。之后把密钥搬进钥匙串或环境变量,旧备份定期清理。如果你用 dotfiles 仓库同步 ~/.claude/,把 settings.json 的 env、~/.claude.json 和 backups/ 都排除在外。

常见坑

相关

本页目录