保护你的项目和 API 密钥
你好,我是鱼皮。
很多没有编程基础的同学在用 AI 做项目时,完全不考虑安全问题。反正代码能跑就行,至于安全不安全,等出了问题再说。但实际上,一个安全问题可能会毁掉整个项目。
我见过有人因为 API Key 泄露,一夜之间被刷了几千。也见过有人的数据库被删,所有用户数据都没了。至于那些大公司的项目,但凡出点儿问题,都会引起轩然大波。
这篇文章,我就来讲讲 Vibe Coding 中最容易忽视的安全问题,以及如何避免它们。
在所有安全问题中,API Key 泄露是最常见、也是最致命的之一。
API Key 就像你家的钥匙,有了它,就能使用某个服务。比如 OpenAI 的 API Key 能让你调用 ChatGPT,Supabase 的 API Key 能让你访问数据库。
问题是,如果这个钥匙被别人拿到了,他们就能冒充你使用这些服务。如果是付费服务,他们会花你的钱;如果是数据库,他们可能会读取、修改甚至删除你的数据。
API Key 最常见的泄露方式是:直接写在代码里,然后上传到 GitHub。
很多同学可能会这样写调用 AI 大模型的代码:
``typescript
// ❌ 千万不要这样做!
const OPENAIAPIKEY = 'sb-yupi-abc123def456...';
const response = await fetch('https://xxx/v1/chat/completions', {
headers: {
'Authorization': Bearer ${OPENAIAPIKEY}
}
});
`
然后把代码推送到 GitHub。
结果呢?
由于你的 GitHub 项目选择了公开,任何人都能看到你的代码,也就能看到你的 API Key。更糟糕的是,有很多自动化脚本专门在 GitHub 上扫描 API Key,一旦发现就会立刻使用。
我听说过有位老哥把 OpenAI 的 API Key 直接写在了前端代码里,然后别人直接从浏览器的开发者工具里找到了他的 API Key,几个小时内就被刷了上千。等他发现时,钱已经花光了。
这个教训告诉我们:API Key 泄露不是小事,一定要重视。
既然不能把 API Key 写在代码里,那应该怎么做呢?
正确的做法是使用环境变量。
环境变量是存储在系统或运行环境中的配置信息,不会被包含在代码里。
在项目根目录创建一个 .env 文件:
OPENAIAPIKEY=sb-yupi-abc123def456...
SUPABASEURL=https://xxx.supabase.co
SUPABASEANONKEY=eyJhbGci...
DATABASEURL=postgresql://...
在代码里通过 process.env 访问这些变量:
`typescript
// ✅ 正确的做法
const OPENAIAPIKEY = process.env.OPENAIAPIKEY;
const response = await fetch('https://xxx/v1/chat/completions', {
headers: {
'Authorization': Bearer ${OPENAIAPIKEY}
}
});
`
确保 .env 文件不会被上传到 GitHub:
.gitignore
.env
.env.local
.env..local
为了让其他人知道需要哪些环境变量,创建一个 .env.example 文件:
OPENAIAPIKEY=youropenaiapikeyhere
SUPABASEURL=yoursupabaseurlhere
SUPABASEANONKEY=yoursupabasekeyhere
DATABASEURL=yourdatabaseurlhere
这个文件可以上传到 GitHub,因为它不包含真实的密钥。
这里有一个重要的区别:前端代码是公开的,后端代码是私密的。
在前端(浏览器中运行的代码)中,即使你用了环境变量,最终这些值还是会被打包到 JavaScript 文件里,用户可以通过开发者工具看到。所以,绝对不要在前端代码中使用敏感的 API Key!
正确的做法是:
通过代码举一些例子:
`typescript
// ❌ 不要在前端直接调用 OpenAI
// 前端代码
const response = await fetch('https://api.openai.com/v1/chat/completions', {
headers: { 'Authorization': Bearer ${OPENAIAPIKEY} }
});
// ✅ 应该这样做 // 前端代码:调用自己的后端 const response = await fetch('/api/chat', { method: 'POST', body: JSON.stringify({ message: userMessage }) });
// 后端代码:调用 OpenAI export async function POST(request: Request) { const { message } = await request.json();
// 在后端使用 API Key
const response = await fetch('https://api.openai.com/v1/chat/completions', {
headers: { 'Authorization': Bearer ${process.env.OPENAIAPIKEY} },
body: JSON.stringify({ messages: [{ role: 'user', content: message }] })
});
return response;
}
`
如果是生产环境,建议使用专门的密钥管理服务,比如 Vercel 的环境变量管理、AWS Secrets Manager、HashiCorp Vault 等。这些服务提供了更安全的密钥存储和访问控制,大公司一般会这么做。
除了 API Key 泄露,还有一些常见的安全问题。
SQL 注入是最经典的安全漏洞之一。如果你直接把用户输入拼接到 SQL 查询里,攻击者可以通过特殊的输入来执行恶意的 SQL 语句。
`typescript
// ❌ 危险:SQL 注入风险
const query = SELECT FROM users WHERE email = '${userEmail}';
// ✅ 安全:使用参数化查询
const query = 'SELECT * FROM users WHERE email = ?';
const result = await db.execute(query, [userEmail]);
`
好在,如果你用的是 Supabase、Prisma 等现代工具,它们会自动帮你防止 SQL 注入。但如果你写原始 SQL,一定要注意这个问题。
XSS(跨站脚本攻击)是指攻击者在你的网站上注入恶意脚本。
比如,如果你直接把用户输入的内容显示在页面上:
攻击者可以输入 正确的做法是: React 默认会转义所有内容,除非你用 CSRF(跨站请求伪造)是指攻击者诱导用户在已登录的网站上执行非预期的操作。 比如你登录了银行网站,然后在另一个标签页打开了一个恶意网站。这个恶意网站里有一段代码,会自动向银行网站发送转账请求。因为你还在登录状态,银行网站会认为这是你本人的操作,就执行了转账。这就是 CSRF 攻击。 防御 CSRF 有 3 种常用方法: 1)使用 CSRF Token:服务器生成一个随机令牌,每次表单提交时都要带上这个令牌,服务器验证令牌是否正确。 2)使用 SameSite Cookie 属性:设置 Cookie 的 SameSite 属性,让浏览器只在同站请求时发送 Cookie。 3)验证请求的 Referer 头:检查请求是从哪个网站发起的,如果不是自己的网站就拒绝。 如果你用的是 Next.js、Nuxt.js 等现代框架,它们一般会自动处理 CSRF 防护。 不要相信前端的任何验证! 前端验证只是为了用户体验,真正的验证必须在后端做。 举一些代码例子: // ✅ 安全:在后端验证
// 前端
function AdminPanel() {
const { data, error } = useFetch('/api/admin/data');
if (error) return // 后端
export async function GET(request: Request) {
const user = await verifyToken(request);
if (!user.isAdmin) {
return new Response('Forbidden', { status: 403 });
}
// 返回数据
}
如果你的项目用了很多第三方包,这些包也可能有安全漏洞。 城门失火殃及池鱼,建议定期运行 如果发现漏洞,运行下列命令,它会自动更新有漏洞的包。 对于无法自动修复的漏洞,要手动检查并决定是否需要更换包。 每次发布项目前,建议结合 AI + 人工过一遍这个清单。 毫无疑问,AI 也能帮你发现并修复安全问题。 你可以让 AI 帮你审查代码的安全性: AI 会给你详细的安全分析。 发现问题后,让 AI 帮你修复: 但要注意,不要完全依赖 AI 的安全建议。AI 可能会遗漏一些问题,或者给出不够安全的方案。你要结合自己的判断,必要时查阅官方文档或者找多个 AI 大模型确认。 除了 AI,还可以使用专门的安全扫描工具: 这些工具能自动发现很多安全问题。 安全不是一次性的工作,而是要养成习惯,时刻铭记着。 给每个用户、每个服务只分配必要的权限,不要给多余的权限。 比如,如果一个 API Key 只需要读取数据,就不要给它写入权限。如果一个用户只是普通用户,就不要给他管理员权限。 这样,即使某个密钥或账户被盗,损失也会小一些。 不要一个 API Key 用到天荒地老。定期更换密钥,比如每 3 个月或每 6 个月换一次。 大多数服务都支持创建多个 API Key。你可以先创建新的 Key,更新到项目中,确认没问题后,再删除旧的 Key。 很多 API 服务都提供了使用量监控和告警功能,记得开启,及时发现异常。 如果你的 API 调用量突然暴增,可能是 Key 被盗用了。如果有人尝试多次登录失败,可能是在暴力破解密码。 安全漏洞会不断被发现,软件包也会不断更新修复漏洞。定期更新你的依赖包,关注安全公告,及时修复已知的安全问题。 即使做了所有防护,还是可能出问题。建议定期备份数据,能让你在最坏的情况下也能恢复。 如果你使用了 Supabase 等第三方后端服务,可能会自动备份。如果是自己的数据库,要设置定期备份。 安全问题往往是最容易被忽视的,因为它不像功能或性能那样直观。但一旦出了安全问题,后果可能是灾难性的。 最后总结一下本文的要点: 安全是一个持续的过程,不是一劳永逸的。保持警惕,定期检查,才能保护好你的项目和用户。 希望这些安全防护技巧能帮你避免常见的安全问题,让你的 Vibe Coding 项目更加安全可靠。 学习辛苦了,给自己加个鸡腿 🍗,吃完就出发! 1)鱼皮 AI 导航网站:AI 资源大全、最新 AI 资讯、免费 AI 教程 2)编程导航学习圈:学习路线、编程教程、实战项目、求职宝典、交流答疑 3)程序员面试八股文:实习/校招/社招高频考点、企业真题解析 4)程序员写简历神器:专业模板、丰富例句、直通面试 5)1 对 1 模拟面试:实习/校招/社招面试拿 Offer 必备typescript
// ❌ 危险:XSS 风险
function Comment({ text }) {
return
,这段脚本就会在其他用户的浏览器中执行。

typescript
// ✅ 安全:React 会自动转义
function Comment({ text }) {
return
dangerouslySetInnerHTML。所以,除非必要,否则不要使用 dangerouslySetInnerHTML。
`CSRF 攻击
身份验证和授权
typescript
// ❌ 不安全:只在前端检查
function AdminPanel() {
const isAdmin = localStorage.getItem('isAdmin') === 'true';
if (!isAdmin) return `
npm audit依赖包的安全
命令检查漏洞。
bash
npm audit fix
四、安全检查清单
密钥和敏感信息
用户输入验证
身份验证和授权
HTTPS 和传输安全
依赖和第三方服务
错误处理和日志
五、让 AI 帮你做安全检查
markdown
请从安全角度审查这段代码,找出潜在的安全问题:
【贴上你的代码】
重点检查:
`
markdown
你提到了这段代码有 SQL 注入风险。请给我一个安全的实现方案,使用参数化查询。
这里的用户输入没有验证。请添加验证逻辑,确保邮箱格式正确,密码长度至少 8 位。
使用安全扫描工具

六、安全开发的习惯
最小权限原则
定期轮换密钥
监控异常活动
保持更新
备份数据
写在最后
推荐资源