第2回で見たMoltbook事件を、もう一度思い出してください。
150万件のAPIキーが漏れた事件。原因の一つは、万能鍵をガラス張りの場所に置いたことでした。
今回は、鍵の種類と置き場所を一枚の地図にします。
APIキーの超基礎、つまり「AIに鍵そのものを渡さない」「設定ファイルに直書きしない」は、Claude Code入門のAPIキー安全講座で扱いました。今回はその続き、公開するアプリでの鍵の運用です。
- 同じ「キー」なのに、なぜ扱いが正反対なのか?
- 環境変数って、結局どこにあるのか?
- ローカルとデプロイ先で、なぜ二重に登録するのか?
この3つを解いていきます。
ㅤ
鍵には2種類ある
Supabaseを例にすると、プロジェクトには最初から2種類の鍵があります。
ブラウザ側のコードで使う前提の鍵。
例えるなら病院の入館証です。持っていれば建物には入れますが、カルテ庫は開きません。この鍵でできることは、前回かけたRLS(受付係)が全部チェックします。
だから、開発者ツールで見られても設計上は問題ない。ただしRLSが機能していれば、です。
サーバー側だけで使う管理者鍵。
例えるならマスターキーです。RLSを素通しして、全テーブルを読み書きできます。受付係は、この鍵の前では仕事をしません。
これがブラウザに届いた瞬間、第3回で作った防御はすべて無効になります。置き場所は、次に説明する「環境変数」一択です。
第2回の3大事故のうち2つは、この表の右側の鍵が左側の場所に置かれたことで起きています。
鍵の強さと、置き場所の公開度は、反比例させる。 これが原則です。
ㅤ
環境変数は「サーバー側の金庫」
では「サーバー側に置く」とは、具体的にどうするのか。
答えが環境変数です。コードの外側にある入れ物に鍵を入れておき、コードには「金庫のこの引き出しを開けて」という指示だけを書きます。
// NG: 鍵そのものをコードに書く(ブラウザに届けば全公開、Gitにも残る)
const supabase = createClient(url, "eyJhbGciOiJIUzI1NiIs...");
// OK: コードには「引き出しの名前」だけを書く
const supabase = createClient(url, process.env.SUPABASE_SERVICE_ROLE_KEY);
ローカル開発では、この金庫の中身を .env というファイルに書きます(Vercelデプロイ回で登場済み)。.env はGitに含めない。ここは次回の主役なので、予告だけしておきます。
視点
「NEXT_PUBLIC_」の意味を知っておく
Next.js製アプリでは、環境変数の名前が NEXT_PUBLIC_ で始まるものだけがブラウザに届きます。つまりこの接頭辞は「この変数は全世界に見せる」という宣言です。anon keyには付けてよく、service_role keyに付けたら事故。AIが書いたコードでこの接頭辞を見たら、「これは見せてよい値か?」と一度立ち止まる癖をつけてください。
ㅤ
デプロイ先には、デプロイ先の金庫がある
ここでつまずく人が多いポイントです。
ローカルの .env は、あなたのPCの中だけの金庫です。VercelやCloudflareにデプロイしたアプリは、あなたのPCを読みに来ません。だからデプロイ先のダッシュボードに、もう一度鍵を登録します。
| 場所 | 金庫の名前 | 特徴 |
|---|---|---|
| 自分のPC | .env ファイル | Gitに含めない。ローカル開発用 |
| Vercel | Environment Variables | Sensitive指定にすると、登録後は値を誰も再表示できない |
| Cloudflare Workers | Secrets | varsと別枠。登録後は値が二度と見えない |
VercelのSensitive指定やCloudflareのSecretsは、「登録した本人すら後から見られない」のが特徴です。不便に見えますが、これが正しい設計です。見る必要が出たら、元の発行元(Supabase等)で確認するか、新しい鍵に替えます。
明日のアクション
今日中にやる点検
- 自分のアプリのコードを
service_roleで検索し、フロントエンド側のファイルに出てこないことを確認する NEXT_PUBLIC_付きの環境変数を一覧にし、全部「見せてよい値」であることを確認する- デプロイ先の環境変数登録で、秘密の鍵がSensitive(またはSecrets)になっているか確認する
ㅤ
今日のまとめ
3行で振り返ります。
- 鍵には入館証(anon)とマスターキー(service_role)があり、扱いは正反対
- 秘密の鍵はコードに書かず環境変数へ。
NEXT_PUBLIC_は「全世界に見せる」宣言 - ローカルの
.envとデプロイ先の金庫は別物。デプロイ先ではSensitive/Secrets指定を使う
ㅤ
次のレッスン
金庫の使い方は分かりました。残る大穴は、Gitの履歴です。うっかりコミットした鍵は、削除しても履歴に残る。次回は、混入を機械的に防ぐ仕組み(Push Protection)と、漏れてしまった日の正しい手順を覚えます。
ㅤ
参考・出典
- Anthropic公式. "API Key Best Practices". https://support.claude.com/en/articles/9767949-api-key-best-practices-keeping-your-keys-safe-and-secure
- Supabase公式. "Understanding API Keys". https://supabase.com/docs/guides/api/api-keys
- Vercel公式. "Sensitive Environment Variables". https://vercel.com/docs/environment-variables/sensitive-environment-variables
- Cloudflare公式. "Workers Secrets". https://developers.cloudflare.com/workers/configuration/secrets/
