我使用 Vibe Coding 在前端编写了一个 API 密钥,结果被黑客入侵并被收取了高额费用。以下是一些示例和安全措施。

我使用 Vibe Coding 在前端编写了一个 API 密钥,结果被黑客入侵并被收取了高额费用。以下是一些示例和安全措施。

“Vibe 编码”是快速构建应用程序的方法,重点是“使其运行”,作为一种现代开发风格,它正在变得越来越流行。

特别是使用Supabase或者Firebase等BaaS,只需要几行代码就可以完成身份验证和数据库操作,这对于快速原型设计和UI改进非常有用。

但另一方面,也很容易犯下危险的错误,例如直接在前端写入 API 密钥或秘密信息这会带来意外黑客攻击或高额账单的风险

本文通过实际的例子和演示,清晰地解释了为什么不应该将私钥写入前端。
介绍实现 vibe 编码与安全性兼顾的具体措施和设计要点

如果您使用氛围进行编码,那么这是必读内容!

这是每个 Web 应用程序开发人员都应该至少阅读一次的安全圣经。
系统地了解攻击原理和应对措施,为编写安全代码奠定基础。

*链接包含附属链接。希望这对您购买书籍有所帮助。

目录

什么是Vibecoding?为了追求效率,风险往往被忽视

如今,我们经常会听到“氛围编码”这个词。
简单来说,这是一种以“让它工作”为首要目标的开发风格,并借助人工智能和便捷工具来保持良好的节奏。

例如,如果您使用 Supabase 或 Firebase,则可以在前端一站式编写登录、数据库连接和显示,并立即在浏览器中查看结果。
当您体验到这种感觉时,许多人会一头扎进去,想着“可以了,没问题!”,而没有深入思考设计和安全性。

然而,如果不加考虑地部署,可能会遇到
意想不到的陷阱事实上,有很多情况下,API 密钥等重要信息会从前端暴露在外。

比你想象的更多的人只是因为某些东西“有效”而部署它们,并向世界泄露危险的信息。

这样的写法真的是错误的吗?

如今,AI 辅助编程已是司空见惯,越来越多的情况是代码编写者没有意识到其中存在风险。
代码运行正常,没有错误,而且是由 AI 生成的……在这种情况下,它更不可能引起怀疑。

例如,如果您直接在前端编写 API 密钥和令牌,或者如果您不创建后端并且让所有事情都在前端处理,那么它
可能一开始会起作用,但实际上很容易从外部利用它

这些“我们不知不觉中做的事情”累积起来,有时会导致信息泄露、高额账单等严重问题

当您在前端写入 API 密钥时会发生什么?

通常会生成处理从登录过程到完全在前端连接到外部 API 的所有事务的代码

此时,AI 会“自然地”建议一种配置,其中 API 密钥和身份验证令牌等秘密信息存储在前端

乍一看,它似乎工作正确,看起来很正常,
但是如果使用此配置进行部署,那么应该在服务器端保持安全的秘密将会暴露并被用户的浏览器看到。

当秘密就在前面时会发生什么?

  • 可以通过浏览器访问轻松提取
    →即使未显示在画面上,也可以通过查看通信内容和代码来获取密钥。
  • 此密钥允许“其他人”操作外部服务
    →通常受限制的操作(例如数据库访问、AI API 和电子邮件发送)现已完全开放。
  • 按次付费 API 会导致即时且高额的费用
    。欺诈性地使用 ChatGPT 和外部电子邮件分发可能会导致每晚产生数万至数十万日元的费用。
  • 情况下,泄露机密会直接导致数据泄露
    → 例如,在 Supabase 这样的案例中,只需一个密钥就可以读取整个数据库。

“把秘密留在前台”就像“出门前把家门钥匙插在前门上”一样。

实际损害案例:API密钥泄露造成的问题

您可能会想,“API 密钥出现在首页上真的那么糟糕吗?”
然而,实际上已经有几个由氛围编码产生的项目因 API 密钥而造成严重损害的案例

Lobable.dev 造成的实际损害

Lovable.dev作为一个 AI“氛围编码”平台正备受关注。
虽然它允许开发者几乎无需编写代码即可轻松构建应用程序,但在安全设计方面却存在不少不足之处。

一些使用Lovable.dev发布的应用程序存在
敏感信息泄露的情况,例如身份验证密钥和电子邮件地址事实上,已有确认的案例显示,OpenAI API和Google Maps API的密钥被嵌入到前端,导致未经授权的使用

仅在一天之内就产生了价值数万日元的请求,因此这可能会产生直接的财务影响,特别是对于使用付费 API 的项目。

一半的 vibe-coded 网站会暴露 API 密钥

另一项研究扫描了 2,000 多个采用 vibe 编码的网站,发现其中约 49.5% 的网站在前端暴露了 API 密钥、JWT 和 Google API 密钥等秘密

这表明,在很多情况下,首要任务只是让代码“运行”,而缺乏安全基础

快速演示:您的 API 密钥真的是隐形的吗?

这里我们将介绍三种常见的 API 密钥处理实现模式(两个错误示例和一个正确示例)。
即使乍一看觉得没问题,但实际上可能存在严重的安全风险。

  • 错误示例 1:
    在前端硬编码 API 密钥。这是一个常见的错误示例。任何人都可以通过查看代码找到密钥。
  • 错误示例 2 :在 .env 中定义 API 密钥
    有时人们会说“如果我在 .env 中定义它就没有问题”,但这与错误示例 1 没有什么不同。
  • API
    服务端的.env ,并通过API与前端通信,密钥不会暴露给用户。

错误示例1:直接在前端写API密钥

首先,您绝对不应该做的事情将密钥直接写入代码中

// app/page.tsx "use client"; import { useState } from "react"; const openaiApiKey = "sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; // ← ⚠️ 危险!直接在前端写! export default function Page() { const [input, setInput] = useState(""); const [response, setResponse] = useState(""); const handleSubmit = async () => { const res = await fetch("https://api.openai.com/v1/chat/completions", { method: "POST", headers: { "Content-Type": "application/json", Authorization: `Bearer ${openaiApiKey}`, }, body: JSON.stringify({ model: "gpt-3.5-turbo", messages: [{ role: "user", content: input }], }), }); const data = await res.json(); const text = data.choices?.[0]?.message?.content ?? "无回应。"; setResponse(text); }; return (<main className="max-w-xl mx-auto p-4 space-y-4"><h1 className="text-2xl font-bold"> 💬 ChatBot 演示(危险的实现示例)</h1><input type="text" placeholder="メッセージを入力..." value={input} onChange={(e) => setInput(e.target.value)} className="w-full p-2 border border-gray-300 rounded" /> <button onClick={handleSubmit} className="bg-blue-600 text-white px-4 py-2 rounded hover:bg-blue-700" >发送</button>{response && (<div className="border p-3 rounded bg-gray-100 whitespace-pre-wrap"> <strong>AI 响应:</strong> {响应}</div> )}</main> ); }

如果您直接在前端写入密钥,它将在构建后包含在 JavaScript 文件中,
因此如果您发布该应用程序,任何人都可以从浏览器查看它

Chrome DevTools 中的“Sources”选项卡,则可以查看已分发的 bundle 文件。
在那里sk-,则可以快速找到硬编码的 API 密钥。

错误示例 ② :在 .env 中定义 API key

有些人认为将其写入 .env 中是安全的,但如果直接从前端代码中引用它,它最终将嵌入到构建的 JavaScript 中并公开。

例如,如果您创建以下代码:

.env

# .env NEXT_PUBLIC_OPENAI_KEY=sk-yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy

页面.tsx

// app/page.tsx "使用客户端"; 从 "react" 导入 { useState }; const openaiApiKey = process.env.NEXT_PUBLIC_OPENAI_KEY; // ← ⚠️ 危险!即使在 .env 中,这也是 NG export default function Page() { const [input, setInput] = useState(""); const [response, setResponse] = useState(""); const handleSubmit = async () => { const res = await fetch("https://api.openai.com/v1/chat/completions", { method: "POST", headers: { "Content-Type": "application/json", Authorization: `Bearer ${openaiApiKey}`, }, body: JSON.stringify({ model: "gpt-3.5-turbo", messages: [{ role: "user", content: input }], }), }); const data = await res.json(); const text = data.choices?.[0]?.message?.content ?? "无回应。"; setResponse(text); }; return (<main className="max-w-xl mx-auto p-4 space-y-4"><h1 className="text-2xl font-bold"> 💬 ChatBot 演示(危险的实现示例)</h1><input type="text" placeholder="メッセージを入力..." value={input} onChange={(e) => setInput(e.target.value)} className="w-full p-2 border border-gray-300 rounded" /> <button onClick={handleSubmit} className="bg-blue-600 text-white px-4 py-2 rounded hover:bg-blue-700" >发送</button>{response && (<div className="border p-3 rounded bg-gray-100 whitespace-pre-wrap"> <strong>AI 响应:</strong> {响应}</div> )}</main> ); }

process.env.NEXT_PUBLIC_OPENAI_KEY,它的值会在构建过程中扩展为字符串。
换句话说,.env,它实际上也会包含在前端 JavaScript 文件中,并且对用户完全可见。

浏览器的“源”选项卡中打开已分发的 bundle sk-已按原样嵌入。
.env ,只要从前端引用它,与直接写入相同的风险

此外,调用 API 时,密钥会被添加到
Authorization 标头因此,“网络”选项卡,这相当于将密钥公开给所有用户。

正确:通过 API

.env中定义的键不应
直接从前端引用如果您使用 Next.js 的 API 路由和路由处理程序,则客户端发送的唯一内容是“用户输入”,并且 OpenAI API 密钥永远不会公开。(即使部署到 Vercel 等平台,相同的配置也能安全运行。)

例如,如果您创建以下代码:

.env

OPENAI_API_KEY=sk-zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz

路线.ts

// app/api/ai/route.ts 从“next/server”导入 { NextResponse }; 导出异步函数 POST(req: Request) { try { const { input } = await req.json(); const apiKey = process.env.OPENAI_API_KEY; // 仅限服务器端,不公开 if (!apiKey) { return NextResponse.json( { error: "服务器配置错误:缺少 OPENAI_API_KEY" }, { status: 500 } ); } const r = await fetch("https://api.openai.com/v1/chat/completions", { method: "POST", headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json", }, body: JSON.stringify({ model: "gpt-4o-mini", messages: [{ role: "user", content: input }], }), }); const data = await r.json();返回 NextResponse.json(data,{status:r.status}); } catch (e) {console.error(e); 返回 NextResponse.json({error:“错误请求”},{status:400}); } }

页面.tsx

// app/page.tsx "使用客户端"; 从 "react" 导入 { useState }; 导出默认函数 Page() { const [input, setInput] = useState(""); const [response, setResponse] = useState(""); const handleSubmit = async () => { const res = await fetch("/api/ai", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ input }), }); const data = await res.json(); const text = data.choices?.[0]?.message?.content ?? "无响应。"; setResponse(text); }; return (<main className="max-w-xl mx-auto p-4 space-y-4"><h1 className="text-2xl font-bold"> 💬 ChatBot 演示(通过安全 API)</h1><input type="text" value={input} onChange={(e) => setInput(e.target.value)} className="w-full p-2 border border-gray-300 rounded" /> <button onClick={handleSubmit} className="bg-blue-600 text-white px-4 py-2 rounded hover:bg-blue-700" >发送</button>{response && (<div className="border p-3 rounded bg-gray-100 whitespace-pre-wrap"> <strong>AI 响应:</strong> {响应}</div> )}</main> ); }

当然,前端没有 API 密钥,因此即使您查看“源”选项卡也找不到它。

此外,授权标头不包含在网络选项卡中,并且由于服务器端代表您向 OpenAI 发出请求,因此不会泄露给用户。

解决方案:从服务器代理请求

从上面的示例中可以看出,在前端处理 API 密钥极其危险,
因此请确保只在服务器端读取API 密钥

如果前端只将用户输入发送到服务器,而服务器代表你向 OpenAI API 发出请求,则 API 密钥不会泄露给外界。这最简单、最安全的操作方式

  • ❌手写内容中复制密钥
  • .env → 构建后嵌入,以便每个人都能看到
  • 通过服务器代理请求→密钥永远不会泄露

如果信息哪怕有一瞬间被泄露给外界,就有可能被盗用,从而产生几十万到几十万日元的账单

还存在许多
其他风险意外在 GitHub 上发布.env。由于机密信息可能会在您不知情的情况下暴露给公众,因此在处理 API 密钥等机密信息时应始终保持谨慎

我也曾发表过一篇文章,利用这种方法妥善解决了安全问题。
如果您想查看详细的代码和部署示例,请参阅这篇文章。

如果您使用氛围进行编码,那么这是必读内容!

如果你读到这里还在想:“哦不,我可能没注意安全问题”,别担心,你还有时间。
应该至少读一遍这本圣经

《系统地学习如何创建安全的Web应用程序,第2版》(作者:Tokumaru Hiroshi)

从漏洞原理到案例和对策阐述了
安全的本质——“为什么危险?”以及“应该如何预防?” 一本真正“系统化”的书,教你攻击流程的具体内容和防御要点。

即使不实际操作,只要掌握一些基本知识,就能有效预防重大事故的发生
如果几千日元就能避免几十万甚至数十万日元的风险,那就没有理由不去读一读。

如果您使用氛围进行编码,那么这是必读内容!

这是每个 Web 应用程序开发人员都应该至少阅读一次的安全圣经。
系统地了解攻击原理和应对措施,为编写安全代码奠定基础。

*链接包含附属链接。希望这对您购买书籍有所帮助。

如果您发现内容困难,
最好请经验丰富的工程师检查

最后,我们现在来看看

正如本文所述,在前端处理 API 密钥极其危险
即使某些操作看似正常,API 密钥实际上暴露给全世界的情况也并不少见。

例如,你真的了解
“用氛围编码”的应用程序如果你仍然不清楚,你应该立即审查其设计并确保其安全性

在人工智能的帮助下,许多人
现在能够编写代码,并感觉“我也能做到”。代码可能看起来运行良好,
如果你忽视了安全问题,导致 API 密钥泄露,你很有可能被收取巨额费用。
如果发生这种情况,承担责任。

如果愿意,请分享!

谁写了这篇文章

这是我开始研究信息安全的博客。作为一名新员工,如果您能宽阔地看着,我会很高兴。
还有Teech Lab,这是一个学习编程乐趣的机会,因此,如果您对软件开发感兴趣,请务必看看!

目录