Rundevlog

小さい会社のしがないエンジニアのブログ

2025.3.16

クライアントサイドでAPIキーどうすればいいんだ問題【ChatGPT会話備忘録】

ChatGPTに教えてもらったことを備忘録としてまとめる。合っているかは保証しません。

今回はクライアントサイドでのAPIキーについて。

1. クライアントにAPIキーを持たせるのは基本NG

ReactとかNext.jsとか、ブラウザで動くアプリでは、アプリのコードはユーザーに丸見え
Webpackでバンドルしようが、Viteで爆速ビルドしようが、結局はJavaScriptとして配られる。

当然、APIキーが埋め込まれていれば、DevToolsでちょっと見ればバレる
難読化しても無意味。誰でも取得できる=誰でも使えてしまう。

いったん漏れれば、APIの不正利用 → サービス側の課金爆発 or 停止、みたいな最悪パターンも普通にある。

2. 環境変数に入れても隠せるわけじゃない

Next.jsならNEXT_PUBLIC_付きの環境変数があるけど、これはビルド時にJSに埋め込まれるだけ

.envに書いてると「サーバーサイドだけで使われる」感が出るけど、NEXT_PUBLIC_API_KEYなんて書いたら、最終的にmain.jsのどっかにベタっと載ってる。

つまり、「環境変数=安全」ではないということ。
クライアントに渡した時点でアウト。

3. 認証と認可で守るべき

APIキーはあくまで**「アクセスの目印」**であって、セキュリティ機構ではない。
言ってしまえば「合言葉」。それだけで門番を突破できるのは雑すぎる。

理想的なのは:

  • ユーザーごとにログイン(=認証)
  • 権限ごとにアクセス制御(=認可)
  • トークン(JWTやOAuthなど)を使ってアクセス権を管理

たとえば、SPAならログインしてIDトークン取得→それをAuthorizationヘッダに付けてAPIアクセス、という流れが定番。

APIキーはログインなしで誰でも使えるので、「公開されてないけど実質オープンAPI」状態になりがち。

4. 認証なしでも使いたいAPIの場合

中には「認証が不要な軽いAPI」もある。
たとえば天気APIや地図APIみたいな、ユーザーの操作によって叩くタイプのもの。

ただし、認証しない=守らなくていいではない。

最低限でも以下の対策は考えるべき:

  • サーバーサイドで一時トークンを発行してJSに埋め込む
  • リファラーチェックで許可されたドメインだけ許可
  • IP制限(Bot除け)
  • CAPTCHAやレートリミットで大量リクエストを防ぐ

正直、ここまでやるくらいならサーバー経由のプロキシを挟んだ方が安全で制御しやすい

5. APIキーを扱うときの最低ライン

シーン方法
サーバーからのアクセスサーバーの環境変数にAPIキーを置く。サーバーから直接叩く
クライアントから直接叩きたい時基本NG。どうしても必要ならCloud Functions等で中継する
Firebase, Stripeなどのケース公開キーと秘密キーを分けて設計。クライアント側は公開キーだけ

特にFirebaseやStripeみたいなサービスは「クライアントから叩いてもOKな設計」がされてる。
とはいえ、その前提をよく確認せずにAPIキーを埋め込むのは危険

6. トークンベース認証への移行

APIキーよりも現代的な選択肢は「アクセストークン(JWTなど)」。

AWSなら:

  • Cognitoで認証
  • API Gateway+IAMでトークン制御

Firebaseなら:

  • firebase.auth()でログイン
  • getIdToken()でIDトークンを取得
  • それをAPIのAuthorizationヘッダに付ける

こうすれば、ユーザーごとのアクセス制御ロール管理もできる。
しかもAPIキーより安全。


まとめ

クライアント側にAPIキーを持たせるのは原則NG。
APIを守るなら:

  • トークンベースの認証(JWT、OAuthなど)
  • サーバー経由でプロキシする構成
  • CORS、レート制限、IP制御などの併用

これが基本。