すべての解説
深刻度:重大流出したシークレット

クライアントサイドのJavaScriptに露出したAPIキー

ブラウザに送られるもの——インラインスクリプト、バンドルされたJS、source map——は誰でも読めます。フロントエンドのコードに埋め込まれたシークレットキー(OpenAI、Stripeのシークレット、AWS、データベースURL)は、実質的に公開されているのと同じです。

これは何か

ビルドツールは、コンパイル時に環境変数をインライン展開します。クライアントのコードでシークレットを参照すると、それはすべての訪問者がダウンロードするJavaScriptバンドルに含まれてしまいます。

重要な区別があります。publishable/anon キー(Stripeの pk_live、Firebaseのweb設定)は公開されることを前提に設計されていますが、シークレットキー(sk_live、service-role キー、プロバイダーのAPIキー)はそうではなく、決してブラウザに届いてはいけません。

なぜ重要か

漏洩したプロバイダーのキーは、誰にでもあなたのアカウントで利用量を積み上げさせ——LLMの請求、SMSの料金、クラウドの費用——あるいはそのキーが許可するデータにアクセスさせてしまいます。

攻撃者は大規模にJavaScriptバンドルをスクレイピングし、キーのパターンを探しています。コミットされたシークレットは、公開後たいてい数分以内に悪用されます。

直し方

シークレットはサーバーに置く

サードパーティのAPIは、ブラウザからではなく、サーバーのルートやバックエンドから呼び出してください。ブラウザはあなたのエンドポイントと通信し、キーはエンドポイントが保持します。

// app/api/summarize/route.ts (server-only)
export async function POST(req: Request) {
  const { text } = await req.json();
  const r = await fetch("https://api.openai.com/v1/responses", {
    method: "POST",
    headers: { Authorization: `Bearer ${process.env.OPENAI_API_KEY}` },
    body: JSON.stringify({ model: "gpt-4o-mini", input: text }),
  });
  return Response.json(await r.json());
}
NEXT_PUBLIC_ プレフィックスは意図的に使う

Next.jsでは、NEXT_PUBLIC_ のプレフィックスが付いた変数だけがブラウザに露出します。このプレフィックスの後ろにシークレットを置かないでください。公開しても安全な値にのみ使いましょう。

漏洩したキーをローテーションする

シークレットが一度ブラウザに配信されたら、失効させて再発行してください。次のビルドから削除しても、すでにスクレイピングされたコピーは無効になりません。

FAQ

Stripeの publishable キー(pk_live)はフロントエンドにあると問題ですか?

いいえ。publishable キーは公開される前提のものです。リスクはシークレットキー(sk_live)で、これはサーバーサイドにとどめる必要があります。

キーを難読化するだけではだめですか?

だめです。難読化は簡単に元に戻せます。唯一の対策は、シークレットをクライアントから完全に排除することです。

あなたのアプリは大丈夫ですか?

AppSafeなら、この問題を含む数十項目を1回の無料スキャンでチェックできます。

アプリを無料でスキャン