在前端页面直接调用 OpenAI API 无法避免密钥暴露,最安全的方式是通过后端服务器或 Serverless 函数中转请求,确保密钥仅存储在受信任的服务端环境中。
先说结论:任何试图在浏览器端隐藏 API 密钥的方案都存在被提取风险,必须将密钥保管在后端。
- 先判断:确认当前代码是否将 sk- 开头的密钥写在了前端 JavaScript 或打包资源中。
- 优先做:搭建后端代理接口或使用 Next.js API Routes 接管所有 OpenAI 请求。
- 再验证:在浏览器开发者工具 Network 面板确认请求不再直接发往 api.openai.com。
快速处理思路
不需要执行单一命令,而是调整架构流向。前端只负责发送业务参数给自有后端,自有后端负责携带密钥调用 OpenAI 接口。
适用场景:所有涉及敏感密钥调用的 Web 应用、小程序或移动端 H5。
操作动作:移除前端代码中的 process.env.OPENAI_API_KEY 引用,新建/server/api/chat 接口。
风险边界:即使使用环境变量打包,前端构建后的代码仍可被反编译,不能依赖构建时隐藏。
为什么会这样
浏览器端代码默认是公开的,用户可以直接查看网络请求和源代码。
任何放在前端项目里的密钥,最终都会下载到用户浏览器中。攻击者可以通过开发者工具 Network 标签页拦截请求头,或直接查看打包后的 JavaScript 文件提取字符串。OpenAI 官方明确建议不要在客户端代码中暴露 API 密钥,因为一旦泄露,他人可以消耗你的配额或产生高额费用。
分步处理
第一步:移除前端密钥
检查前端代码库,搜索 sk- 关键字。删除所有直接实例化 OpenAI SDK 的代码,例如 new OpenAI({ apiKey: '...' })。
第二步:搭建后端代理
使用 Node.js、Python 或 Next.js 创建一个新的 API 接口。在该接口内部读取服务端环境变量中的 OPENAI_API_KEY。
配置片段示例(Node.js Express):
app.post('/api/chat', async (req, res) => { const response = await openai.chat.completions.create({ model: 'gpt-3.5-turbo', messages: req.body.messages }); res.json(response); });
第三步:修改前端请求
将前端 fetch 地址从 https://api.openai.com/v1/chat/completions 改为自有域名下的 /api/chat。
回滚提醒:保留旧版本代码备份,确保后端接口连通后再切换前端请求地址。
怎么验证是否生效
打开浏览器开发者工具,进入 Network 面板。刷新页面并触发调用功能。
检查请求列表:不应出现指向 api.openai.com 的请求。所有请求应指向你的后端域名。
检查请求头:前端发出的请求头中不应包含 Authorization: Bearer sk-... 字段。
日志确认:在后端服务器日志中确认看到了来自前端的请求,且后端成功向 OpenAI 发起调用。
常见坑
跨域问题:前端调用自有后端接口时可能遇到 CORS 报错,需在后端配置允许跨域。
费用失控:代理接口如果没有鉴权,可能被他人滥用。建议在后端接口增加用户登录态验证或频率限制。
流式响应:如果需要打字机效果,后端需支持 Server-Sent Events (SSE) 并将 OpenAI 的流式数据转发给前端,不能简单返回 JSON。
常见问题
把密钥混淆或加密放在前端可以吗?
不可以。前端代码最终需要在浏览器运行,密钥必须解密后才能使用,这个过程会被调试工具捕获。
使用 Next.js 的 API Routes 安全吗?
安全。Next.js 的 pages/api 或 app/api 目录下的代码仅在服务端运行,不会打包发送到客户端。
密钥泄露后该怎么办?
立即在 OpenAI 平台删除泄露的密钥并生成新密钥,同时检查 usage 页面确认是否有异常消费。
参考来源
OpenAI Help Center, Best practices for API key safety, https://help.openai.com/en/articles/5112595-best-practices-for-api-key-safety