跳到正文
DEV Community· KeyVault Edge·· 5 小時前AI 評分69

VITE_ 前端 API key 會進入公開 JavaScript bundle,文章整理洩漏後果及三種修復方法

Your VITE_ API key is public. Here's what happens next, and three ways to fix it

AI 導讀

在前端使用 VITE_、NEXT_PUBLIC_* 或 REACT_APP_* 環境變數讀取 AI 或支付服務的 API key,會令 key 出現在訪客下載的 JavaScript bundle 中。

正文

If your frontend reads an AI or payments key from import.meta.env.VITE_SOMETHING, that key is in the JavaScript bundle every visitor downloads. Same for NEXT_PUBLIC_* in Next.js and REACT_APP_* in Create React App. Putting it in a .env file changes where it's stored on your laptop, not where it ends up.

You can check in ten seconds: open your deployed site, open DevTools → Sources, and search the bundle for your key's prefix (sk-, AIza, sk_live_).

What happens after a key ships in a bundle

Automated scanners crawl deployed sites and public repos for those prefixes. Developers have described the results publicly this year on Google's own forum, for example about $6,000 in roughly 40 minutes from an AI Studio sample exported to Vite, and about $2,200 from a VITE_GEMINI_API_KEY used as a shared fallback.

Providers have added protections (Google now rejects unrestricted Gemini keys and offers project spend caps; OpenAI has project limits), but those work per project or account, not per key, and they don't stop the key from being copied.

If it already leaked: the first hour

  1. Revoke or regenerate the key in the provider console. Don't wait to check whether it was used.
  2. Check usage for the window since the deploy: unfamiliar models, regions or volume.
  3. Restrict every remaining key to only the APIs it needs, and set a budget alert.
  4. Remove the key from the bundle (below) before you deploy again.
  5. If it was ever committed, it's also in git history. Rewrite history or make the repo private, and turn on GitHub push protection.

Three ways to keep the key out of the bundle

1. A small backend endpoint. A serverless or edge function holds the key as a secret; your frontend calls the function. Free, and the right answer if you'll also add rate limiting and per-user budgets.

2. The provider's own client-side option, if it has one. For example, Firebase App Check with Firebase AI Logic for Gemini on mobile and web.

3. An edge proxy with per-key limits. You store the real key once and your app sends a stand-in token instead. The proxy adds the real key and forwards the call, and each token carries its own rate limit, allowed endpoints, spend cap and an off switch. I build one of these, KeyVault Edge. You can watch it allow one request and block two misuse attempts on a live demo, no signup.

One honest limit for option 3 (and for any token a browser can see): the token can still be copied and replayed from a server. The point is that a leaked token has hard limits and can be revoked in one click without rotating the provider key, so the damage is bounded.

A quick checklist

  • [ ] No provider key in any VITE_, NEXT_PUBLIC_ or REACT_APP_ variable
  • [ ] Bundle searched for key prefixes after every deploy
  • [ ] Each key restricted to the APIs it needs
  • [ ] Budget alert and spend limit set at the provider
  • [ ] Push protection on for the repo

How did your key end up in the frontend? I'd like to hear what made it the easiest option at the time.

來源:DEV Community · dev.to