我最近帮朋友做代码评审,第一眼就看到项目顶层模块里躺着一整行硬编码的 API Key,就那么明晃晃写在业务代码里,旁边还有一长串聊天记录和数据库连接串。我试了试,那把 Key 居然还有效,可以直接调用付费模型接口。这不是个例。过去半年我翻过的 AI 应用源码里,十个有九个在凭证管理上处于裸奔状态:有人把 Key 提交进 Git 历史,有人把 .env 文件发给别人,有人让 AI 编程助手直接把密钥写进代码再粘贴回项目里。AI 应用开发真正的大坑,往往不是模型效果调不好,而是你自己的代码把钥匙挂在了大门口。
这篇文章我想把 AI 应用场景下凭证管理这件事彻底讲透。从为什么 AI 应用特别容易翻车,到本地开发、生产发布、密钥扫描、泄露应急的完整闭环,全部按我真实踩坑和修复的经验来写。适合正在做 AI 应用、AI Agent、大模型 API 集成的开发者,也适合团队里负责代码安全和工程规范的同事。看完之后你至少能回答三个问题:我的密钥现在暴露在哪些地方?怎么系统地排查和修复?以后怎么防止再犯?
1. 为什么 AI 应用是凭证泄露的重灾区
1.1 AI 应用的凭证密度远超传统项目
传统后端应用通常只需要一两个数据库密码、一个对象存储 Key,顶多再来个支付回调密钥。但 AI 应用完全不同。一个稍微正规点的智能应用,凭证清单是这样的:
- 大模型平台的 API Key,可能是两家三家一起接;
- Embedding 模型的调用凭证;
- 向量数据库的账号密码或者连接字符串;
- 对象存储、文件服务的访问密钥;
- Agent 调度平台、工作流编排服务的 Token;
- 定时任务、消息队列、监控上报的认证信息;
- 如果接入了外部工具、插件、搜索 API,每多一个工具就多一组凭证。
我之前接手过一个 AI 客服机器人,光靠读配置就数出十七组秘密信息。但凡这些凭证里有一组是以明文形式出现在代码仓库里,整个系统就等同于把内部网络结构、数据源位置、第三方服务账号全部公之于众。麻烦的是,AI 项目的迭代速度又太快,开发者在兴奋地把 Agent 跑通的时候,很少有人会停下来问一句:这些 Key 我到底放哪了?
1.2 “先跑起来再说”的开发节奏天然埋雷
AI 应用开发节奏跟传统业务系统不太一样。传统系统上线有明确的测试环境、预发布环境、生产环境,密钥配置一般有专人管理。AI 项目的起点往往是个人原型:本地开个 Notebook,或者用 Cursor 这类 AI 编程工具一顿生成。跑通 Demo 之后再往团队项目里搬。搬代码的时候,最容易出事的不是模型调用逻辑,而是藏在代码里的各种明文 Key。
我见过最常见的流程是这样的:本地调试时为了让代码少出问题,直接把 Key 赋值给一个全局变量,接着在 Cursor 对话框里让它修代码。AI 编程助手读到了这个 Key,甚至会在生成新文件时顺手把它一起带进去,因为对模型来说,这段字符串跟普通代码没有区别。然后你把这个新文件提交到 GitHub,Key 就这么润物细无声地进了公网。
还有更隐蔽的路径:为了调通某平台的 API,开发者会去网上找示例代码。示例代码里经常写着一串看起来很像真的 Key 的占位符,有时候甚至真的就是作者自己的测试 Key。开发者图省事,直接复制粘贴。这个动作会带来双重风险:一是你自己的代码里混进了别人的凭证,出事后根本说不清是谁在调用;二是你无形中养成了“代码里可以放 Key”的肌肉记忆。
1.3 AI Agent 让凭证暴露面进一步扩大
传统应用里,凭证的用途很单纯:程序在运行时读取一次,然后和服务端通信。AI Agent 出来之后情况变了:Agent 要调用大模型,还要根据模型输出决定调用哪个工具,工具再返回结果给模型,循环往复。这个过程中,凭证可能要被多个中间层传递。
最典型的一个坑:Agent 在循环推理时,框架会把工具返回的原始信息塞进上下文,上下文一旦被完整记录到日志系统里,就可能把某个工具的 AccessKey 间接带出来。还有的 Agent 框架支持“自动修复工具调用错误”,当工具返回权限不足时,Agent 会自动尝试重新认证,日志里很自然地会打印认证参数。AI 应用的调试日志又出了名的啰嗦,开发者为了看 Agent 到底干了啥,经常把整段请求体和响应体打到日志里。密钥就这样随着日志进了 ElasticSearch、进了日志平台、进了第三方分析系统。很多人只在代码扫描里找硬编码,却忘了日志系统其实是最容易被忽视的凭证泄露出口。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 一组 Key 泄露的实际路径拆解
2.1 硬编码进源码文件,最原始却最普遍
直接写死在 .py、.js、.java 文件里的情况,比大家想象中多得多。我见过的最离谱版本,是把 Key 存在一个命名为 config.py 的文件里,然后这个文件被当成普通模块提交到了仓库。还有人把它命名为 constant.py,觉得“常量”听起来就安全。实际上不管叫什么都一样:任何能访问仓库的人都能读到,任何被拉取的镜像、任何被构建的产物都可能把它带出去。
为什么硬编码这么难戒?因为本地验证最快。你新建一个脚本,然后设置环境变量、再写 dotenv 加载逻辑,整个过程至少多花三分钟。对于只想快速看一次模型返回效果的开发者来说,直接在文件里贴 Key 是最短路径。问题在于,这个文件不会在你验证完之后自己消失。它会被重构、被复制、被别的模块 import,最后被提交。我自己就干过这蠢事,后来是凭据被平台发邮件提醒异常调用才发现。
2.2 .env 文件被提交进 Git 仓库
这是第二常见的泄露方式,而且比硬编码更难清理。很多人还是知道不能把 Key 提交进代码文件的,于是他们用了环境变量文件 .env。但他们忘记把 .env 加进 .gitignore。更麻烦的是,某些项目初始化模板里自带 .env.example,开发者复制了一份改成 .env,填入真实 Key。这时如果仓库根目录的 .gitignore 规则不全,.env 就会被 git add 进去。
一旦提交,问题就彻底升级了:即使你现在把文件删掉再提交一次,Key 仍然存在于 Git 历史里。任何人只要 clone 仓库并翻历史就能找到。任何一个代码托管平台的公开仓库、任何一个团队成员本地的克隆副本,都等于你亲手送出去的钥匙。
我的建议是,团队项目从一开始就用 .gitignore 把 .env、.env、.env. 全部按死,并且约定:真实 Key 永远不允许出现在任何文件里,哪怕是临时文件。这条约定要写进 README,最好做成 pre-commit 钩子去强制校验。
2.3 日志、调试输出与链路追踪把 Key 带出去
这类泄露通常不是开发者主动为之,而是日志系统太热情。常见的三个场景:
- 框架的全局异常处理器把所有异常上下文打出来,而某个 HTTP 请求的 Header 里正好带着 Authorization: Bearer xxx,Key 跟着堆栈一起输出。
- Agent 工具调用的输入输出被完整记录,工具参数里包含目标系统的连接凭证。
- 链路追踪系统把数据库连接字符串、Redis 地址、服务间调用凭证当作 span attribute 记录,为了方便排查问题,结果全部进了追踪平台。
日志类泄露最可恶的地方在于:它不在代码仓库里,常规代码扫描扫不到。很多人觉得 Git 仓库里没有 Key 就万事大吉,实际上外部服务方通过日志问询发现了你的 Key 正在被滥用,你才知道出了大事。
排查日志泄露时,不要只盯着应用日志。要检查请求日志中间件、ORM 的 SQL 日志、HTTP 客户端调试模式、AI 框架内部的 token 用量追踪模块。凡是会输出对象完整结构的日志代码,都必须加白名单或者脱敏过滤。
2.4 AI 编程助手帮你“复制粘贴”出更多带 Key 的代码
这是 AI 编程时代特有的一种泄露路径。用 Cursor、Copilot 这类工具的时候,对话上下文里经常含有密钥,不管是你在提问里贴了代码片段,还是 AI 在生成配置时自己造了一个。模型的训练目标和习惯决定了它会模仿上下文里的风格,如果你的代码里已经有硬编码 Key,AI 生成的新模块很大概率会复制同样的模式,把 Key 写进新的位置。
更隐蔽的一种情况是,你让 AI“把这个模块从一个文件拆成两个文件”。AI 会忠实地把整段代码搬过去,包括里面那行密钥。你如果没仔细审查,新的文件又被提交,泄露面就从 1 个文件变成 2 个甚至更多。所以我现在用 AI 写代码有一个铁律:先把所有明文 Key 替换成环境变量引用,再让 AI 做任何重构。顺序反了,AI 就会帮你把 Key 复制得满项目都是。
3. 凭证管理的正确姿势:从本到端全链路方案
3.1 本地开发:环境变量 + dotenv + 严格忽略规则
本地开发可以用环境变量,也可以用 dotenv 类方案。核心原则只有一条:代码文件里不允许出现真实的秘密信息,密钥要么从进程环境里读,要么从不会被 Git 跟踪的本地文件里读。
以 Python 项目为例,我习惯这样组织:
bash复制# .env 文件位于项目根目录,加入 .gitignore
OPENAI_API_KEY=sk-real-key-here
DATABASE_URL=postgresql://user:pass@localhost:5432/db
python复制# config.py
import os
from dotenv import load_dotenv
load_dotenv() # 仅本地开发时加载
OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY")
if not OPENAI_API_KEY:
raise RuntimeError("缺少 OPENAI_API_KEY 环境变量")
这里有个关键点:config.py 必须做的事是“从环境里读取并校验”,不要在 load_dotenv() 之外写任何默认值。我见过有人在代码里写:
python复制API_KEY = os.getenv("OPENAI_API_KEY", "sk-fallback-key")
这个 fallback 值就是给自己埋雷。一旦环境变量没配好,程序会静默使用兜底密钥。等哪天你把这段代码分享给别人的时候,兜底密钥也一起出去了。
.env.example 可以提交,但里面只能放占位符:
bash复制OPENAI_API_KEY=your_openai_api_key_here
DATABASE_URL=your_database_url_here
.gitignore 里写死这些规则:
gitignore复制.env
.env.*
!.env.example
3.2 代码运行时:通过配置中心读取,不经过源码
本地开发之后是生产环境。生产环境如果还靠手动 export 环境变量,一旦服务器重启、容器重建、编排系统更新,Key 很容易弄丢或者写进启动脚本里。启动脚本一旦进入仓库,又是泄露。
更稳的做法是使用密钥管理服务。各家云厂商都提供这类服务,名字可能叫 KMS、Secret Manager、Vault 之类,核心能力是一样的:
- 密钥存放在独立于代码库的加密存储中;
- 应用通过 SDK 或者服务身份动态获取;
- 可以设置自动轮换;
- 访问行为有审计日志。
AI 应用接 KMS 的时候,常见的架构是这样:应用启动时向密钥管理服务申请密钥,缓存在内存里,定期刷新或者被服务端强制失效后重新获取。代码里只需要配置一个“密钥别名”或者“密钥引用路径”,不包含真实值。
比如你在代码里会看到这类配置:
yaml复制llm:
api_key_ref: secret/ai-project/prod/llm-api-key
vector_db:
password_ref: secret/ai-project/prod/vector-db-password
程序通过统一的 SecretClient 去解析这些引用。好处是,就算某个开发者把配置文件完整截图发到群里,别人拿到的也只是别名而不是真实密钥。坏处是 KMS 引入了一定的学习和维护成本。但我个人强烈建议,任何有外部用户或者涉及真实数据的 AI 应用,都必须走这一步。省下来的成本是暂时的,泄露后的账单和公关成本才是无底洞。
3.3 权限最小化与服务隔离
凭证管理不只是“把 Key 藏好”,还包括“就算 Key 被人拿到,他能造成的破坏也有限”。这里有三条经验:
第一,每个服务用独立的 Key,不要全局一把 Key 走天下。AI 应用中,前台聊天和后台批量任务如果用同一个模型平台密钥,一旦前台被探测到 Key,后台的额度也会被打光。相互独立的 Key 能把爆炸半径限制在单个服务。
第二,能配权限范围的平台尽量配到最小。模型平台一般支持只读、推理调用、管理权限等不同等级的 Token。不要为了省事直接生成一个全权限管理员 Key 放到应用代码里。代码运行需要什么权限,就只给它什么权限。我去审核过的项目里,至少三分之一的应用使用的 Key 权限过大,有些甚至能访问组织账单信息,而应用本身只需要文本生成。
第三,测试环境、预发环境、生产环境的凭证必须完全分开。千万不要觉得“用同一个 Key 问题不大”。你永远不知道测试环境的代码会不会被实习生一键部署到公网,也永远不知道测试数据库里造出来的数据会不会包含真实用户信息。混用环境凭证是应急响应时最痛苦的情况,因为出了事你根本不知道是哪个环境的 Key,也不知道该先回收哪一把,只能把所有环境的全部轮换一遍。
3.4 密钥轮换要形成机制
很多团队设置了密钥,但一年都不轮换。如果某个 Key 已经泄露而你没有发现,它的有效期越长,损失越大。密钥管理要配置自动轮换。没有条件用云服务的自动轮换,也要在日历里加一个固定周期的提醒,季度或者是半年一次。
轮换密钥时有一个注意点:先部署新 Key,确认切换完成后再吊销旧 Key。直接吊销旧 Key 会导致正在运行的服务瞬间大量报错。顺序应该是:
- 在密钥管理服务里生成新版本;
- 更新应用配置指向新版本;
- 逐步重启或刷新应用实例;
- 观察日志、错误率和调用成功率;
- 确认所有实例都正常后,吊销旧版本。
对于 AI 模型 API 这种按量计费的服务,轮换之后还要核对账单。如果旧 Key 在吊销前仍然有调用记录,说明有另一个系统还在使用同一个 Key,需要顺藤摸瓜找到那个系统,而不是直接放弃处理。
4. 用静态扫描揪出已经泄露的凭证
4.1 扫描整个 Git 历史,而不是只看当前文件
如果项目已经在用 Git,第一步不是去改现在的代码,而是扫描整个提交历史。因为当前代码里没有 Key 不代表历史里没有。常见做法是用 gitleaks 这类开源工具。
先安装。macOS 可以用 Homebrew,其他环境直接下载二进制也行:
bash复制brew install gitleaks
在项目目录启动全量扫描:
bash复制gitleaks detect --source . --report-path gitleaks-report.json --report-format json --verbose
它会把每一次提交里出现的疑似密钥、Token、私钥片段全部抓出来,报告里会显示提交哈希、文件路径、匹配规则和泄露内容的前几个字符。第一次跑往往结果很多,不要慌,先按规则分类处理,有些可能是误报,比如测试用的假 Key、文档中的示例占位符。
误报的处理方式是给项目加一个 .gitleaks.toml 配置文件,把特定的测试字符串加入允许列表,但要确保只是绕过规则而不是真把 Key 放行。配置文件这样写:
toml复制[allowlist]
description = "项目内已知的测试占位符"
regexes = [
'''sk-test-[a-zA-Z0-9]{20}''',
'''your_openai_api_key_here''',
]
4.2 常见扫描规则与正则识别原理
静态扫描工具的原理并不神秘。它们维护了一批正则表达式规则,去匹配常见的密钥格式。例如 OpenAI 格式的 Key 普遍以 sk- 开头,GitHub Token 有明确的 ghp_ 前缀,AWS Access Key 是固定的 AKIA 开头加一长串 Base62 字符,Google API Key 有固定的前缀模式。
除了规则匹配,还可以用熵检测发现不规则的高随机字符串。因为有些私有系统的 Token 没有特定前缀,但长度和字符分布符合高熵特征。工具会计算出字符串的信息熵,超过阈值就标记为可疑。
团队如果用的是自建 CI,可以把 gitleaks 加进流水线,在每次 push 或者打标签时自动扫描。命令是:
bash复制gitleaks protect --source . --staged --verbose
这条命令专门检查将要提交的内容。如果命中任何规则,进程会以非零状态退出,从而阻断这次提交。把它接到 pre-push 钩子里最合适。
4.3 在 Git 历史中彻底清除密钥
扫描结果确认有真实 Key 已经进了历史之后,光是删除当前代码和轮换密钥还不够。密钥必须轮换,这个是第一位。历史清理只是减少凭证进一步扩散的风险,不能作为救命稻草。
清理历史最稳妥的工具是 git filter-repo,它可以把特定文件内容从所有提交中抹除。基本流程如下:
bash复制# 先备份仓库
git clone --mirror https://your-server/your-project.git project-backup.git
# 安装 filter-repo 后执行
git filter-repo --invert-paths --path .env --path config/secret.py
上面命令会删除所有历史提交里的 .env 和 config/secret.py。清理完成后,需要所有协作者重新 clone 仓库,并且强制推送覆盖远程。这里特别提醒:filter-repo 会重写整个提交历史,所有基于旧历史的本地分支、PR 引用都会失效,必须在团队协调好之后统一操作。
清理之后再做一次全量扫描确认为空。对我实际经验来说,清理历史只是心理安慰,真正有效的是把密钥当作已泄露处理,立即到对应平台吊销掉,同时去查这个 Key 是否已有异常调用记录。
4.4 用 pre-commit 钩子把新密钥挡在门外
扫描发现的成本永远低于修复。在代码进入提交之前直接拦截,才是最高效的手段。推荐用 pre-commit 框架统一管理 Git 钩子,在仓库根目录放一个 .pre-commit-config.yaml:
yaml复制repos:
- repo: https://github.com/gitleaks/gitleaks
rev: v8.18.1
hooks:
- id: gitleaks
安装一次:
bash复制pip install pre-commit
pre-commit install
之后每次 git commit,pre-commit 都会自动跑一遍 gitleaks,发现疑似密钥就拒绝提交。这套方案需要每个开发者本地都安装一次 pre-commit。为确保所有人都遵守,在 CI 里也加一道同样的扫描,作为兜底。
5. 凭证泄露之后的应急响应清单
5.1 第一步:确认泄露范围和当前影响
发现凭证可能泄露之后,先冷静,不要急着删除代码。马上要回答的问题是:
- 泄露的是哪个平台的哪把密钥?
- 这把密钥出现在哪里:Git 公共仓库、日志系统、聊天工具、别人机器?
- 这个 Key 在对应平台上的权限范围是什么?
- 它是否已经被使用过,是否存在异常调用?
如果是模型平台的 Key,先去后台查看调用记录和用量曲线。关注异常时间段内是否有来自陌生 IP 或者陌生 Model 的请求。如果平台支持设置消费上限和告警,立刻设为较低的阈值。
如果泄露的 Key 关联了支付方式,立刻检查账单,确认没有产生预期外的费用。AI 模型 API 按量计费,千万级 Token 的异常调用不需要太久就能打出一笔不小的账单。
5.2 第二步:吊销密钥并启动轮换
确认泄露之后,不要试图保留旧 Key,哪怕你觉得它可能只是出现在内网仓库里。立即执行吊销。吊销之后,马上创建新 Key 并部署到正常服务。
这里有个细节:新密钥不要直接复制到原来的配置文件就完事。配置文件的访问权限、所在服务器、读取方式都要重新检查一遍。如果原来 Key 是写在普通文本文件里的,这次改成从环境变量或者密钥管理服务读取。否则你只是在同一个漏洞上换了把新锁,下次还会以同样的方式泄露。
5.3 第三步:排查异常访问与数据风险
撤销 Key 只是止血,更需要关注的是攻击者利用 Key 访问了什么。模型平台的 Key 能调用哪些模型、能不能读取历史对话记录、能不能访问知识库、能不能读取文件,都要排查。AI 应用最怕的不是多花一点模型调用费用,而是训练数据、私有知识库内容、用户会话记录被以合规途径拉走。
这一步要检查关键服务的访问日志,精确到时间点。用撤销前的时间作为下限,追溯这个 Key 的所有调用行为。把异常调用的时间、IP、请求内容、返回内容单独归档,作为后续追查和漏洞复盘的材料。
5.4 第四步:复盘漏洞根源并修复
应急响应做完,最重要的事情是把导致泄露的根因干掉。常见根因和对策如下:
| 根因 | 对策 |
|---|---|
| 硬编码在代码文件 | 代码扫描 + pre-commit 钩子强制拦截 |
| .env 被提交 | .gitignore 严格规则 + 历史清理 |
| 日志输出完整请求上下文 | 日志脱敏中间件 + 密钥字段屏蔽 |
| AI Agent 工具调用日志含凭证 | 工具返回结果统一脱敏 |
| 第三方依赖示例代码自带 Key | 依赖审查 + 代码生成规范 |
| 开发者聊天窗口黏贴密钥 | 团队规范 + AI 工具策略限制 |
很多团队会在这一步引入一个问题跟踪单,把每一条泄露路径编号记录,修复后还要扫描验证。应急响应没有做完这个概念,只有验证过、确认不再存在才能关闭。
6. AI Agent 特有的凭证管理细节
6.1 不要让模型直接接触密钥原文
在 Agent 架构里,模型会根据系统提示词决定调用哪些工具,工具需要凭证才能访问外部服务。一个常见的错误是把所有工具的凭证都以环境变量形式注入到 Agent 的运行时容器里,同时把“读取环境变量的能力”暴露给模型。某些 Agent 框架甚至支持让模型自由执行 Shell 命令或 Python 代码——那也就意味着,只要模型输出一段读取 env 的代码,密钥就会被工具结果当成普通字符串返回到上下文里,再被记录到日志。整个过程完全不需要攻击者参与。
正确的模式是:把凭证交给 Agent 的执行层,不让大模型有从环境里读取密钥的途径。工具函数的认证逻辑在工具内部完成,模型只需要看到工具调用成功或失败的状态。可以理解为“门禁卡在保安手里,访客只需要说要进哪栋楼,保安自己刷卡”。绝对不要让访客自己去口袋里翻门禁卡。
6.2 工具返回内容必须脱敏
即使模型没有主动读取密钥的能力,工具的返回内容里也可能夹带机密信息。比如一个读取数据库的工具,查询出错时可能把完整的 JDBC 连接字符串返回来。再比如 HTTP 工具在请求失败时把请求 Header 原样输出,Authorization 字段就暴露了。
给 Agent 接入工具时,必须加一层统一的输出过滤器:任何工具返回内容经过这层过滤时,凡是符合密钥格式的字符串,一律替换成 ***REDACTED***。可以用正则匹配常见密钥前缀,也可以加入自定义敏感词表。这样即使模型不小心拿到了包含凭证的返回内容,实际输出给模型的时候已经不可用了。
6.3 Cursor 这类 AI 编程助手的使用红线
AI 编程助手是生产效率利器,但也是密钥复制器。我的使用规范三条:
第一条,工作目录里的 .env 文件不要用 AI 助手的“添加到上下文”功能。有些 AI 编程工具会读取项目文件,开发者为了方便让它改配置,直接让它读 .env。一旦 Key 进入上下文,后续生成的文件、重构的代码都可能携带它。
第二条,代码评审类任务里如果出现疑似密钥字符串,先在编辑器里手动替换为环境变量引用,再提交给 AI 进行分析。不要试图让 AI“忽略那段 Key”,模型对上下文的模仿倾向会让它越界。
第三条,警惕 AI 自动补全的配置项。当你在编写一个 SDK 初始化代码时,AI 有时会直接补全一个完整的初始化函数,包括 api_key="sk-..."。这串 Key 通常是模型编造的,不真实,但代码风格会诱导你把自己的 Key 填入同样的位置。所以要仔细审阅每次 AI 补全的代码,关键字就是 api_key、secret、token、password 这几个词。
6.4 示例代码和开源项目里的占位符规范
AI 项目大量依赖官方示例代码和开源项目二次开发,这里同样有凭证管理的坑。平台方给出的示例里,密钥字段应该写成明确的占位符,比如:
python复制client = OpenAI(
api_key=os.environ.get("OPENAI_API_KEY"),
)
但现实中的示例代码质量参差不齐,很多直接写 api_key="sk-xxx"。如果你照抄,本地跑不通,你会填上自己的真实 Key,之后这段代码又会被提交。所以我说,看到任何示例代码里的密钥占位符,马上把整行替换成环境变量读取,再跑测试。不要怀着“先跑通再改”的心态,你后面大概率会忘。
如果你是开源项目的维护者,在 README 和示例文件里要主动使用环境变量方案,并且把 .env.example 提交到仓库里。这既是对使用者负责,也在降低自己项目被贡献者用真实 Key 污染的风险。
6.5 密钥的度量衡:额度、速率与告警
AI 平台的密钥还有一个特殊的风险维度:用量。和数据库密码不同,模型 API 的密钥天然对应费用。就算密钥没有被滥用,一个内部系统配置错误导致的死循环也可能触发大量模型调用,一天烧掉一个月预算。所以密钥管理绝不能漏掉用量监控这一环。
每个密钥单独创建之后,立刻设置月度额度上限、单日调用次数限制和速率限制。部署告警规则,把模型调用量、费用增长率和异常错误码纳入监控。一旦发现某个密钥调用量突增,具备直接吊销权限的负责人要能在 5 分钟内完成处置。不要再等事后对账单心疼,提前设好阈值,自动化止损才是正经做法。
7. AI 应用凭证管理常见问题速查
| 症状 | 根因 | 解决方案 |
|---|---|---|
| 模型平台突然产生大额费用 | API Key 泄露并被滥用 | 立即吊销 Key,设置限额,审查历史调用 |
| Git 仓库扫描发现 .env 文件 | .gitignore 缺失或规则不全 | 清理历史,添加规则,轮换其中所有密钥 |
| 代码评审发现硬编码 Key | 开发习惯 + 缺少拦截 | pre-commit 钩子 + 团队规范 + 替换为环境变量 |
| AI 助手生成的代码出现假 Key | 模型补全行为 | 审查每次生成代码,统一环境变量规范 |
| 工具返回内容里带连接字符串 | 异常处理输出完整对象 | 工具返回过滤层 + 脱敏 |
| 日志平台里搜到明文 Token | 全量请求日志导致 | 日志脱敏 + Header 过滤白名单 |
| Agent 报错后提示权限不足 | 凭证配置不正确 | 检查运行环境变量,不要将调试信息暴露到用户端 |
| 轮换密钥后服务持续报错 | 还有实例没切换到新 Key | 分批重启,观察,旧 Key 先别急着吊销 |
这张表我建议贴到团队 Wiki 里,不要每次出问题都从头查一遍。表格里的每一行都是我见过真实案例后才总结出来的,看起来简单,踩一次坑就长记性了。
8. 最后分享一点个人经验
写了这么长,最后说点我自己早期踩过的坑。我刚做 AI 应用的时候,没把凭证管理当回事,总觉得项目小、代码是私有的,不会有问题。后来我把一个带完整 Keys 的演示项目推到公开仓库,还是为了“挂出来给简历加分的”。幸亏三天后我准备提交新功能时偶然发现自己把真 Key 放进去了。那三天里到底有没有人扫走,我到现在都不知道,只能把所有相关的密钥全部轮换,项目也转成了私有。
那次之后我给自己定了一套规矩,现在送给正在读这篇文章的你:
每新建一个 AI 项目,第一步先配好 .gitignore 和 pre-commit 钩子,再开始写任何代码。核心代码评审清单里,固定检查一条:全局搜索 sk- 开头、AKIA 开头、ghp_ 开头、eyJ 开头这几种特征字符串。任何需要真实密钥的操作,只在本地终端环境变量里配置,不写进任何文件。交付或者部署前跑一遍 gitleaks,结果为空才算完。
这套流程听起来繁琐,实际执行十分钟以内就能完成。但它能帮你挡住至少九成的凭证泄露事故。AI 应用的安全不是部署完再加固的,而是从你写下第一行调用大模型的代码时,就在密钥管理上做对选择。如果你能顺手把团队里那几个做 AI 原型的人拉过来,给他们也看一眼这篇里的清单,你以后做代码评审会省心非常多。
