← 学习路线

密钥与配置

密钥应该放在哪、交给谁、用完怎么办?为什么配置明明是对的,程序却在用另一份?

课型:鉴别·约 20 分钟·5 个术语

先看出事的那一刻

2026 年 7 月 27 日,自动驾驶知识站要配置域名。AI 教站长在 Cloudflare 后台建一把只管域名解析的令牌,"拿到后发我",收到后把它写进了项目的配置文件。第二天,部署前端需要更大的权限。这一次 AI 说"别贴在聊天里,会留在会话记录里",建议站长用一条命令自己写进文件;站长还是把账户 ID 和令牌直接贴进了对话。

之后的两个月里,AI 提醒作废九次,一次也没有执行。写这节课的几个小时前,同一把令牌还被用来部署了旧域名的跳转。

同一个项目里,还有一次和配置有关的事故,方向正好相反:配置写对了,程序却没用上。

这节课要回答的是:密钥应该放在哪、交给谁、用完怎么办?为什么配置明明是对的,程序却在用另一份?

装备几个词

为什么要懂

AI 替你做了

AI 能替你创建令牌、写配置文件、调用平台接口,把部署一路做完,还会记得提醒你“用完记得作废”。

留给你的

决定密钥放在哪、给多大权限、什么时候作废,并且真的去作废。最后这一步只有你能在后台完成。

不懂的代价

令牌原文散落在会话记录、命令和自动摘要里,拿到的人能以你的身份改域名、发布网站;你却说不清它现在还在哪些地方。

密钥能放在哪

位置能不能放为什么
前端代码不能会被下载到每个访客的浏览器里
代码仓库不能历史里删不干净(第 9 课)
聊天记录、命令原文不能会被保存、被摘要、被搜到
本地的 .env(被 git 忽略)可以只在这台电脑上
托管平台后台的环境变量可以由平台保存,只在运行时交给程序

这次两把令牌,都碰了第三行:一把是 AI 要来之后写进文件的,原文就留在它当时执行的命令里;另一把直接贴进了对话。之后 AI 调用接口时,又把令牌原文写进了十六条命令,连自动生成的对话摘要里都原样带着它。

对照同一时期的另一件事:AI 调用 Railway 接口时,每次都在运行时从配置文件里读取令牌,会话记录里一处原文都没有。差别不在工具,而在写法。

最小权限,加上过期时间

第一把令牌做得不错:只能修改一个域名的解析记录。第二把是账号级的,后来为了部署,又加上了发布网站的权限。

给 AI 用的令牌,按这个顺序想:

  1. 这次任务到底要调用哪些接口?只勾那几项权限。
  2. 能不能限定到具体的域名或项目,而不是整个账号?
  3. 设一个过期时间:任务做完之后,它会自己失效。
  4. 任务结束,立刻去后台作废。

第 4 步最容易拖。它不难,只是要你自己登录后台,而那一刻,事情已经做完了。

配置明明是对的

7 月 26 日,导师要接入第三方模型。冒烟测试五项全部失败,报错是 401 Invalid bearer token。配置文件里的端点和密钥都没错,可启动日志里写着:

injected env (2) from .env
端点 https://api.anthropic.com

文件里写了 3 个变量,只注入了 2 个;端点也不是配置的那个。原因是这个测试在 Claude Code 里运行,环境里已经有一个同名的 ANTHROPIC_BASE_URL,而 dotenv 默认不覆盖已经存在的变量。第三方的密钥,就这样被发到了另一家公司的接口上。

AI 看到这两行日志,十几秒就定位了原因。能这么快,全靠启动时打印了实际生效的端点:配置有好几个来源时,程序最好在启动时说清楚"我最后用的是哪一个"。

深潜override 解决了一个问题,也带来了一个+

修法是给 dotenv 打开 override:让 .env 覆盖环境里已有的变量。可这样一来,优先级整个反了过来:任何一台机器上残留的 .env,都会压过平台后台配置的值。线上这次没出事,只是因为打包镜像时恰好排除了 .env。

它还有一个副作用:.env 里的每一个变量都会被灌进程序的运行环境,包括应用根本用不到的那把 Cloudflare 令牌。

配置的来源和优先级,最好写在一个地方说清楚:哪些来自平台、哪些来自本地文件、哪些有默认值,冲突时听谁的。

找茬

下面是 E2E Review 的后端配置、本地配置文件(只保留变量名),以及 AI 调用接口时的一条命令(节选)。找出让密钥更容易泄露、或者让程序悄悄用错配置的地方。

这段 JS / .env / Shell 里埋了 5 处问题。点击你觉得有问题的行,至少找出 3 处再揭晓。

查看代码与答案(5 处问题)
 1  // server/config.mjs(后端配置,节选)
 2  // override 必需:宿主机跑 Claude Code 时已注入 ANTHROPIC_BASE_URL=官方端点,
 3  loadEnv({ override: true });
 4  // 生产环境必须显式配置的秘密,缺一不可——绝不给默认值兜底
 5    jwtSecret: process.env.JWT_SECRET ?? "dev-only-change-me",
 6  
 7  # .env(本地配置文件,值已隐去)
 8  ANTHROPIC_AUTH_TOKEN=[已隐去]
 9  DATABASE_URL=[已隐去]
10  CLOUDFLARE_API_TOKEN=[已隐去]
11  
12  # AI 调用 Cloudflare 接口时执行的命令(值已隐去)
13  export CF_T='[已隐去]'; curl -s -H "Authorization: Bearer $CF_T" …
  • 第 3 行 · 中危 · 优先级被整个反了过来:为了绕开宿主环境里的同名变量,这里让 .env 覆盖一切。副作用是:任何一台机器上残留的 .env,都会压过平台后台配置的值。线上这次没出事,只是因为打包镜像时恰好排除了 .env。 该问的话:配置有几个来源?谁优先?线上会不会读到本地的 .env?
  • 第 5 行 · 中危 · 注释说绝不兜底,下一行就兜了底:上面的注释写着“绝不给默认值兜底”,这里却给了一个写在代码里的默认签名密钥。是否用上它,只看 NODE_ENV 是不是 production:哪天换一种方式启动、忘了设这个变量,登录签名就会悄悄用上这个人人都看得到的值。 该问的话:如果线上忘了设置 NODE_ENV,登录签名用的是哪把密钥?
  • 第 8 行 · 中危 · 同一把密钥,六个项目共用:这把大模型密钥被贴进过四次聊天,现在放在六个项目的配置文件里,线上也是它。任何一处泄露,等于全部泄露;想换掉它,要改七个地方。 该问的话:这把密钥还用在哪些地方?每个项目能不能各用各的?
  • 第 10 行 · 高危 · 部署用的令牌,混进了应用的配置:应用根本不读这个变量。它是 AI 配置域名时写进来的那把令牌,此后一直没作废;又因为上面的 override,每次启动都会被灌进程序的运行环境。 该问的话:这个配置文件里,哪些变量是应用运行需要的,哪些是别的用途留下的?
  • 第 13 行 · 高危 · 令牌原文写进了命令:命令会原样留在会话记录里。同一把令牌就这样被写进了十六条命令,连自动生成的对话摘要里都有它。更好的写法是在运行时从文件读取,命令里只出现文件名。 该问的话:你执行的命令里有没有出现密钥原文?能不能改成运行时从文件读取?

快测

1. AI 说:“把 API Key 发给我,我帮你配好。”最好的做法是?

查看选项与答案
  • A. 直接贴进对话,这段对话只在你和 AI 之间,不会留下痕迹——对话不会用完就丢,会被保存、被摘要、被搜到,还可能被原样写进它执行的命令。这次的令牌,就是这样散进了十六条命令和自动摘要。
  • B. 提交进代码仓库,让 AI 从仓库里读,之后再从文件里删掉——历史里删不干净,密钥一旦提交过,之后从文件里删掉,它也还留在提交记录里。
  • C. 自己写进被 git 忽略的 .env,只把变量名告诉 AI(正确)——密钥原文不经过对话,也不进仓库;AI 只需要知道变量名,运行时照样读得到。

让 AI 知道密钥在哪,而不是让它看到密钥是什么。

2. 一把令牌已经贴进过聊天。现在最该做的是?

查看选项与答案
  • A. 把令牌挪进被 git 忽略的 .env,不再贴进聊天——换个地方存放,改变不了原文已经留在会话记录和命令里;拿到旧原文的人,照样能用它。
  • B. 到后台作废这把令牌,再建一把只含所需权限的新令牌(正确)——这是唯一可靠的补救:旧令牌一旦失效,它散落在哪里都没用了。新令牌只勾需要的权限、设上过期时间,用完再作废。
  • C. 删掉聊天里的那条消息,再清空这段会话里的全部历史记录——记录可能已经被保存、被摘要,还被原样写进过命令。删掉一条消息、清掉一段记录,都收不回那些已经散出去的副本。

泄露过的密钥,只有作废才算处理完。

3. .env 里配的是 A 端点,程序实际请求的却是 B 端点。最可能的原因是?

查看选项与答案
  • A. 变量名和代码里读取的名字对不上,程序退回了默认的端点地址——配置文件里的端点和密钥都没写错。日志显示文件里的 3 个变量只注入了 2 个,被跳过的正是端点,因为环境里已经有一个同名的了。
  • B. 运行环境里已有同名变量,dotenv 默认不覆盖它(正确)——看启动日志里注入了几个变量、实际生效的端点是什么:文件里写了 3 个,只注入了 2 个。这次是 Claude Code 的环境里本来就有 ANTHROPIC_BASE_URL。
  • C. .env 放错了位置,程序根本没读到这个文件——启动日志写着 injected env (2) from .env,文件读到了,还注入了其中 2 个变量。

配置不生效时,先问:程序最后用的是哪一份?

判断时刻

部署需要一把能管理域名、发布网站的令牌,你要让 AI 用它完成部署。

你会怎么交给它?

三个选项各自的代价
  • A. 在后台建一把全权限令牌,贴进对话——考察最省事:一次就能跑通,中途不会卡在权限上。代价是:令牌原文留在会话记录里,权限大到能动整个账号,“用完作废”全靠你之后记得。这一次,两个月都没作废。
  • B. 建一把只含所需权限、带过期时间的令牌,写进被忽略的配置文件,让 AI 在运行时读取——考察多花两分钟:要自己在后台勾权限、设过期时间。但令牌原文不会进入会话记录;即使泄露,能动的范围有限,过期之后也就失效了。
  • C. 不给令牌,让 AI 把命令写出来,你自己执行——考察密钥不出手:最安全:密钥从不经过 AI。代价是每一步都要你来回复制粘贴,步骤一多就很慢,也容易漏掉一步。适合一次性的敏感操作。

密钥的风险不在“给不给”,而在给多大、放在哪、什么时候收回。收回这一步只有你能做,别让它拖成两个月。

带走

下次让 AI 做这件事时,问它

  1. 这个任务需要哪些密钥?每把需要的最小权限是什么、多久过期?
  2. 密钥放在哪个被 git 忽略的文件或平台变量里?你执行的命令里会不会出现密钥原文?
  3. 配置有几个来源(平台变量、.env、代码里的默认值)?谁优先?线上会不会读到本地文件?
  4. 任务结束后,列出这次用过的所有令牌,提醒我逐个作废。

自己验证

  • git check-ignore -v .env:确认 .env 被 git 忽略了。
  • 在会话记录和命令历史里搜一下密钥的开头几位,看它出现在了哪些地方。
  • 到平台后台看一眼令牌列表:每把令牌的权限、过期时间、最后一次使用时间。

密钥交出去之前,先想好它什么时候收回来。