硬编码密钥的真实威胁:删除不等于修复
AI 编辑倾向生成硬编码密钥,一旦进入 git 历史即成永久凭证泄露,删除文件无法消除风险——对 AI 编程工作流的关键安全警示。
AI 编辑倾向生成硬编码密钥,一旦进入 git 历史即成永久凭证泄露,删除文件无法消除风险——对 AI 编程工作流的关键安全警示。
AI 编辑器会把看起来真实的 API 密钥、JWT 密钥和数据库密码直接粘贴到你的源代码中,因为它们的训练数据充满了这样做的教程。
硬编码的密钥一旦被提交到文件中,就会变成活跃凭证,即使你之后删除了这一行,也无法撤销这种暴露。
解决办法是从环境变量中读取每个密钥,并在每次提交前运行密钥扫描器,这样密钥就永远不会进入受追踪的文件。
上周我请 Cursor 在一个个人项目中接入 Stripe。它在大约十秒钟内给了我能用的结账代码。但它同时在第 3 行给了我这个:
const stripe = require('stripe')('sk_live_51H8xY2eZvKYlo2CaBq...');
这是一个活跃的密钥,在我即将提交的文件中。不是占位符,不是 TODO,而是一个实际格式的密钥。AI 没有标记出来。它读起来像普通的设置代码,这正是为什么它很危险。
这是我在 AI 生成代码中最常发现的问题,几乎从不是开发者不小心造成的。这是工具按照训练数据教它的方式做事。
硬编码密钥是指任何直接写入源代码而不是在运行时从环境中加载的凭证。AI 编辑器不断产生这些:
// Cursor 生成的代码
const stripe = require('stripe')('sk_live_51H8xY2eZvKYlo2C...'); // CWE-798
const JWT_SECRET = 'my-super-secret-key-123';
const db = mysql.createConnection({
host: 'prod-db.internal',
user: 'admin',
password: 'Sup3rSecret!2024'
});
# Python 中的同样模式
API_KEY = "sk-proj-abc123def456..." # CWE-798
DATABASE_URL = "postgres://admin:hunter2@prod-db:5432/app"
这些都是有效的凭证。问题不仅仅是它们可见。问题在于一旦你 git 提交,该密钥就会永久存在于你的历史中,即使你在下一次提交中删除了这一行。任何克隆该仓库或读取其泄露镜像的人都会得到这把钥匙。
AI 编辑器硬编码密钥是因为它们训练的代码绝大多数是示例代码,而示例代码内联虚假密钥来保持自包含。每份 Stripe 快速入门指南、每个 JWT 教程、每篇"五分钟连接数据库"的博客文章都在密钥位置放入一个文字字符串,以便代码片段可以直接运行。该模型学到了"设置 API 客户端"意味着"在这里放一个密钥形状的字符串"。
该模型没有概念知道哪些字符串是安全的,哪些字符串保护金钱或数据。对于生成器而言,sk_live_... 和"hello world"只是适合这个位置的 token。它也看不到你的 .env 文件,也不知道你的部署设置,所以内联是总能产生可运行代码的最小阻力路径。
这就是陷阱:输出运行得完美无缺。没有错误。该漏洞在仓库泄露之前是看不见的,而那时密钥已经在你的历史中存在了几个月。
从环境变量加载每个密钥,永远不要让原始凭证进入受追踪的文件。只需两行改动:
// 修复后
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
const JWT_SECRET = process.env.JWT_SECRET;
const db = mysql.createConnection({
host: process.env.DB_HOST,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD
});
# 修复后
import os
API_KEY = os.environ["OPENAI_API_KEY"]
DATABASE_URL = os.environ["DATABASE_URL"]
然后三件事让它真正有效。在你写第一个密钥之前,把 .env 加到你的 .gitignore。运行 gitleaks 作为提交前钩子,这样一个误入的密钥会阻止提交,而不是进入历史。如果有真实密钥曾经被提交过,旋转它,不要只是删除这一行。从当前文件删除密钥会在之前的每个提交中保留它完整无损,所以暴露后唯一安全的做法是撤销旧密钥并签发新密钥。
Q:如果我的仓库是私有的,硬编码密钥仍然是个问题吗?
A:是的。私有仓库会被克隆到笔记本电脑、镜像到 CI 系统、被分叉,有时会被意外公开。无论仓库可见性如何,一旦提交密钥到 git 历史中,就要把它视为已被泄露。
Q:如果我在后来的提交中删除了硬编码密钥,我就安全了吗?
A:不是。Git 保持完整历史,所以密钥仍然可以在早期的提交中读取。对提交的密钥唯一的安全反应是旋转它、撤销旧值并签发新值。
Q:我如何在提交前捕捉到这个?
A:运行密钥扫描器(如 gitleaks)作为提交前钩子,并在 .gitignore 中保留 .env 文件。这个组合阻止密钥到达受追踪文件,远比之后从历史中清理它容易。
我一直在用 SafeWeave 来处理这个。它作为 MCP 服务器接入 Cursor 和 Claude Code,在代码生成时立即使用基于 gitleaks 的扫描器标记硬编码密钥。即使是一个简单的提交前钩子结合 semgrep 和 gitleaks 也会捕捉到这篇文章中的大部分内容。重要的是早点捕捉到它,无论你用什么工具。
在 SafeWeave 博客上阅读完整原文:https://safeweave.dev/blog/why-deleting-a-hardcoded-secret-does-not-fix-it-cwe-798
如需进一步行动,你可以考虑屏蔽此人和/或举报滥用