ChatGPT(OpenAI API)を使ったアプリを作る際、「とりあえず動いた」で公開してしまうと、
APIキーの漏洩 や 想定外の大量リクエスト によって、金銭的・運用的な事故が起きがちです。
ここでは、最低限これだけはやっておきたい対策をシンプルにまとめます。
0. 一番怖い不正利用
一番怖いのは、あなたが作成したサービスの UI を経由した不正利用ではありません。
プログラムを組まれて、あなたのサービスを使うことなく、相手が自分の作ったアプリ(スクリプト)から Workers を直叩きして連打されるケースです。
- 画面操作ではなく、API エンドポイントを直接連打される
- 正規ユーザーの導線を一切通らないため、気づきにくい
- 対策がないと「短時間で上限まで回される」→ 高額請求につながる
そのため本記事で書いている対策は、主に
UI を守るのではなくAPI(Workers)を守ることを目的にしています。
さらに重要な点として、通信内容は簡単に取得できます。
つまり、あなたのサービスを通じて実際に使用された通信と、全く同じ通信内容をそのまま連打するだけで上限まで回されるという状況は、何が何でも回避しましょう。
1. クライアントから直接 OpenAI API を叩かない
もっとも重要なのは、ブラウザやアプリから OpenAI API を直接呼ばないことです。
- APIキーをクライアントに埋め込むと、必ず漏れます
- DevTools、通信ログ、改変リクエストで簡単に抜かれます
必ず Workers / サーバー等を経由してください。
- クライアント → Workers(または任意のサーバー)
- Workers → OpenAI API
- クライアントには「結果だけ」を返す
この構成にすることで、
- APIキーを完全に秘匿できる
- リクエスト制御・検証が可能
- stream 対応も問題なく可能
特に Cloudflare Workers の無料枠 は非常に強力で、個人開発では強くおすすめできます。
2. レート制限(回数制限)を必ず入れる
次に重要なのが 利用回数の制限 です。
最低限、以下のような単位で上限を設けましょう。
- 5分あたり
- 1時間あたり
- 1日あたり
実装は意外と簡単で、
- 各項目について
- 基準時間(例:N分を超えているならば、そのスレッドが基準時間とカウント数をリセット)
- カウント数
- この2つの情報を保存するだけ
というシンプルな構造で十分です。
Workers + KV / Durable Objects / D1 などを使えば、
IP・ユーザーID・APIキー単位 で容易に管理できます。
3. ワンタイムキー(簡易トークン)を発行する
Workers を直接叩かれることを防ぐために、
ワンタイムキー(簡易トークン)を必須にするのも有効な対策です。
ここで重要なのは、
ワンタイムキーの中身を、暗号化した DateTime にするという点です。
基本的な考え方は以下です。
- DateTime をそのまま送らず、必ず暗号化
- クライアントからのリクエストには
oneTimeAPIKey: "hsahjkasdfh"
のようなセットにする - サーバー側で復号し、
- 有効期限内か(送信されて 10 秒以内か)(古すぎる・未来である、そもそも正しい値か)
をチェックする
- 有効期限内か(送信されて 10 秒以内か)(古すぎる・未来である、そもそも正しい値か)
これにより、
- 同じキーの 使い回し
- 過去通信の リプレイ攻撃
- 雑なスクリプトによる連続アクセス
を防ぐことができます。
実装時の注意点として、
- ts や timestamp など、中身が推測できるキー名は使わない (個人的に oneTimeAPIKey が一番やる気を削ぐと思います)
- 暗号化後の文字列も、
- 桁数から時間が推測されないよう
- 先頭に数文字のダミーを付与する
といった工夫を入れると、より安全です。
この方式であれば、
- 特別な認証基盤を作らなくても
- DateTime の比較だけで
- 軽量に「今発行されたリクエストか」を判定
できるため、
個人開発や小規模アプリにちょうど良い現実的な対策になります。
なお、この方式はデコンパイルによって暗号化キーを取得される可能性があるため、決して万全な対策ではありません。
ただし、通信内容のみを解析して破ることは不可能であり、少なくとも「通信を眺めるだけの不正利用」や「雑なリクエストスクリプト」に対しては十分な抑止力になります。
補足として、
ダミーの DateTime を ts: Datetime の数値 として送信しておく方法も、効果は薄いものの推奨できます。
この ts は実際の検証には使わず、
あくまで ダミー用途 として送信します。
- 本命の DateTime は暗号化されたワンタイムキーの中に含める
- ts は意味のない(検証されない) DateTime とする
この構成にすることで、
- 悪用する側が ts の方を本命だと誤認する
- 「DateTime が 2 個ある」という発想に至らない可能性がある
- 雑な解析・スクリプトの手間を増やせる
といった 軽い撹乱効果 が期待できます。
もちろん、この方法だけでセキュリティが大きく向上するわけではありませんが、
コストほぼゼロで追加できる防御層としては十分に意味があります。
本記事で紹介している対策全体と同様に、
これは「破れない仕組み」ではなく、
雑に悪用されにくくするための工夫 として位置付けるのが適切です。
4. 自動チャージ設定について必ず検討する
ChatGPT(OpenAI API)を利用する上で見落とされがちですが、
不正利用が発生すると高額な請求につながる恐れがある点は必ず意識すべきです。
実際、対策が不十分な状態で API キーが漏洩した場合、
数千ドル規模(7000ドル程度は覚悟してください)の請求が一気に発生するケースも現実にあります。理論上は、数万、数十万、数百万、数千万ドルの請求もありえます。設定できる上限額はあくまで「目安」や「運用上のガード」に過ぎず、確実に適用されるものではなく、状況によっては守られない 可能性がある点も踏まえておきましょう。
そのため、
残高の自動チャージ設定を本当に継続すべきかどうかは、一度必ず検討することをおすすめします。
ここで重要なのは、
- 自動チャージを否定すること自体が目的ではない
- 「検討せずに有効にし続ける」状態が危険
という点です。
検討時には、少なくとも以下の2点を天秤にかけてください。
- 自動チャージ:請求が跳ねるリスク
- 不正利用・バグ・想定外のアクセス増加によって
一気に高額請求が発生する可能性
- 不正利用・バグ・想定外のアクセス増加によって
- 逐次チャージ:チャージ金額が大きいことによる残高消失リスク
- チャージした残高は 1年間しか有効でない
- 使い切れなかった分は失効する
この2つのリスクを、
「なんとなく」ではなく 正しく理解した上で選択できているか を自問してください。
小規模・個人開発の場合は特に、
- 自動チャージを無効にする
- チャージ額を極小にする
- 監視・通知を必ず入れる
といった運用も十分に現実的です。
API を守る設計(1〜3章)と、課金を守る判断(本章)はセットです。
技術的対策だけでなく、課金設定そのものも含めて「最低限の安全対策」と考えましょう。
また、ChatGPT 用に 専用のデビットカードを紐づけた上で自動チャージを有効化すれば、
「チャージした残高が失効して消える」というリスクは 極小化できます。
あらかじめ利用上限の低いデビットカードを用意しておくことで、
- 不正利用時の被害額を物理的に制限できる
- クレジットカード全体への影響を避けられる
- 残高を多く抱えずに運用できる
といったメリットがあります。
自動チャージを使う場合でも、
支払い手段を分離し、物理的に上限を絞ることで、リスクを現実的なレベルまで下げることが可能です。
ChatGPT がデビットカードによるチャージを使える間だけ使える裏技ですが、頭の片隅に入れておきましょう。
APIキーの課金について、自動チャージではなく逐次チャージ方式を採用していた場合でも、実際には -5,000 ドルといった残高表示になっている事例が報告されています。
逐次チャージ方式であっても、利用制限や停止処理の反映にタイムラグが生じる可能性があるため、万全な対策とは言えない点を意識する必要があります。
それでも自動チャージと比較すれば、逐次チャージの方が被害を抑えられるケースが多いとは思われます。
-5,000 ドルという表示が直ちに請求確定を意味するのか、それとも将来のチャージ時に相殺される形式なのかは、契約条件や利用状況によって異なる可能性があります。外部から断定することはできません。
-5,000 ドルの表記は、APIキーが流出していた場合や、使用モデルの指定をフロント側に任せていた場合には、特に高額なモデル(例:o1-pro など)を自由に利用できる状態であれば、簡単に成立し得ます。
こうしたケースでは、利用制限や停止処理の反映にタイムラグが生じ、その間に利用が急増した結果として大きな金額が計上されている可能性が考えられるからです。
一方で、サーバー側で使用モデルを固定し、利用量を制御するなどの対策を講じていれば、このようなタイムラグによる影響も含めて、-5,000 ドルの表記が発生する可能性は大きく抑えられるでしょう。
5. 本気のサービスでは正式な認証・セッション管理が必要になる
ここまで紹介してきた対策は、
個人開発・小規模アプリ向けの 最低限かつ現実的な対策 です。
一方で、ユーザー数が増えるサービスや、
継続的な提供・収益化を前提とする 本気のサービス では、
これらだけで十分とは言えません。
その場合は、
- OAuth(Google / Apple / GitHub など)
- セッション管理
- トークンの失効・更新管理
- ユーザー単位での厳密な権限・回数制御
といった 正式な認証・認可の仕組み が必須になります。
サーバー側で署名検証やクレーム検証などの処理を適切に行う前提であれば、フロント側で認証情報を取得し、それをサーバーに提出する設計は妥当です。
えげつない単純化ですが、ログインすると、自分では偽造できず、サーバーだけが本物だと確認できる認証情報を受け取れる、と考えていただければと思います。
リクエストがどのログインユーザーに紐づくものかを特定できるため、ユーザー単位での利用制限やレート制御を実装することが可能です。
IPアドレスや端末情報のみを判定に利用する方式は、フロントエンドで実装している以上、それらの値を書き換えて送信される可能性があるため、十分な対策とは言えません。
一方で、サーバー側で署名検証やクレーム検証を厳格に行う構成であれば、不正利用の手段は大幅に限定されます。想定される主なリスクは、大量のアカウントを作成して認証を通過させる物量攻撃や、正規アカウントを悪用するケースなどに絞られます。
例えば、1 ユーザーあたり 1 分間に 30 リクエストという制限を設けていても、攻撃者が自分で作成した 1,000 件のアカウントについて、それぞれ認証情報を取得・運用できる環境を構築していれば、理論上は1 分間に 3 万リクエストまで拡大します。ユーザー単位の制限のみでは、物量による回避が起こり得る点に留意すべきです。
一般に、防御側の対策は多層的であるほど効果が高く、攻撃者にとってコストが収益を上回る場合、嫌がらせ以外の目的で攻撃を継続する合理性は失われます。
世の中には無数のサービスが存在し、攻撃対象はいくらでも見つかります。そのため、仮にセキュリティレベル80程度まで突破可能な攻撃者であっても、セキュリティレベル 40 のサービスを狙うより、さらに対策の弱いセキュリティレベル 5 のサービスを狙う方が、はるかに低コストで済むという現実もあります。
DateTime ベースのワンタイムキーや簡易レート制限は、
あくまで
- 認証基盤を持たない段階
- 早く公開したいプロトタイプ
- 個人・社内向けツール
で使うための 軽量な防御層 です。
スケールさせる前提のサービスでは、
簡易対策でどこまで守れるか ではなく、
正規ユーザーをどう識別・管理するか に
早い段階で設計を切り替えることを強くおすすめします。
最低限対策 → 正式な認証設計へ
この移行を前提にしておくことが、長期運用では重要です。
6. モデルはフロント側で指定しない
ChatGPT API を利用する際、
使用するモデル名をフロント側から指定させないことも重要な対策です。
モデルの指定は 必ず Workers(サーバー)側で固定してください。
基本方針は以下です。
- Workers 側で使用モデルを決定する
- フロントからは常に
gpt-5-nano
を送信させる
そして Workers 側では、
- 受信したモデル名が gpt-5-nano の場合のみ、内部的に想定しているモデルにマッピングして使用する
- もし gpt-5-nano 以外が送られてきた場合は
- gpt-5-nano Flex として扱う(オススメ)、または
- 明示的に弾く
といった運用を 推奨します。
gpt-5-nano 以外が送られてきた場合に gpt-5-nano Flex として扱うのは、モデル名に pro が入っていた場合、20 秒 Sleep しましょう。この偽装は、攻撃までたどり着いてしまった場合に pro で Dos 攻撃が成功していると確信させる効果があります。
この構成にすることで、
- 高額なモデル(意図しないモデル)を勝手に指定される
- モデル名改変によるコスト攻撃
- フロント改変による想定外の課金
を防ぐことができます。
モデル指定は一見 harmless(無害) に見えますが、
課金と直結するパラメータです。
そのため、
- フロントは「要求内容」だけを送る
- Workers は「どう処理するか」を完全に握る
という責務分離を徹底してください。
これはレート制限・課金対策と同様に、
低コストで実装でき、効果が高い最低限対策の一つです。
gpt-5-nano を使う場合は gpt-5-nano reasoning_effort: "minimal" を推奨します。他のモデルより動作が早く、安い ため、ストレスフリーです。
ex1. 軽量なリプレイ攻撃抑止としての DateTime チャレンジ方式
これは間違いなく必須でない項目です。余談として閲覧頂ければと思います。
本対策はセキュリティ強度としては高いものではありませんが、スクリプトの使い回しや長時間のリプレイ攻撃を抑止する目的 で有効なケースがあります。
仕組みの概要
- クライアントは通信開始時に、サーバーから
暗号化された DateTime(サーバー時刻) を受信します。 - クライアントはその値を 一切加工せず、後続のリクエストに含めてサーバーへ送信します。
- サーバー側では、復号した DateTime が現在時刻から一定範囲内(例:10秒以内)であることを確認します。
- 条件を満たさない場合は、そのリクエストを無効とします。
期待できる効果
・通信内容をそのまま保存・再送信する 単純なリプレイ攻撃 を困難にします。
・有効時間を短く設定することで、長時間後の再送信はほぼ確実に失敗します。
・攻撃者がこの仕組みを回避するには、
- 既存のスクリプトに小規模な修正を施す
- 通信内容を解析する
- 暗号化方式を特定する
- 長文の暗号化キーを導出する
といった作業が必要になります。
これらは、得られる成果に対して 時間的・コスト的に見合わない と判断される事に繋がる可能性があり、攻撃のモチベーションを下げる効果がある可能性があります。
本対策の位置付け
この方式は 解析すれば容易に仕組みが分かる対策 です。
単体で高度なセキュリティを実現するものではありません。
しかし、
・既存のスクリプトに小規模な修正を強制できる
・自動化された攻撃コードをそのまま流用できなくする
・という点で、珍しさによる抑止効果があります。
注意点
HTTPS やトークン認証などの 基本的な対策を置き換えるものではありません。
あくまで「追加の一手」「攻撃コストを上げる工夫」として導入することが前提です。
導入時のデメリット(往復回数が1回増える)
この方式は「サーバーから暗号化 DateTime を受け取り、後続リクエストに付けて返す」ため、設計によっては 通信が1往復増える点に注意が必要です。
レイテンシ増加:体感速度が落ちる(特にモバイル回線・海外リージョンで顕著)
リクエスト回数増加:回数制限(Rate Limit)や同時接続数制限がある場合に悪影響
コスト増:インフラ課金やAPI利用料がリクエスト数に連動していると増加要因
そのため、「そもそものアクセスに要する時間」と「回数制限(もしあるなら)」への影響を前提に評価する必要があります。
適用範囲は限定するのが現実的
本対策は強固な防御というより「攻撃コストを上げる一手」なので、全リクエストに一律適用するよりも、次のように 守りたい箇所だけに絞るほうが実務的です。
高額モデル利用など、コストインパクトが大きいAPIだけ
不正利用されると被害が大きい操作(課金、発行、書き込み系)だけ
怪しいトラフィックが増えたときの段階的導入(オンデマンド適用)
まとめ
最低限やるべき対策は、以下の3点です。
- API は必ずサーバー(Workers)経由にする
- 時間単位の回数制限を入れる
- ワンタイム性のあるキーで雑なアクセスを防ぐ
これだけでも、
- APIキー漏洩
- 想定外の課金
- 悪意のない誤爆アクセス
の多くを防げます。
「ChatGPT を使う=すぐ高コストになる」ではなく、
入口をちゃんと締めるだけで、安全かつ低コストに運用可能です。
個人開発・社内ツールであっても、ぜひ最初から入れておきましょう。
※セキュリティは、思いついた手法が具体的で有効なほど公開すると攻撃者の学習コストを下げてしまい、逆に自分が突破される 可能性が高まるため、詳細が共有されにくい傾向があると、私は勝手に思っています。公開情報を探しても有効な手法が見つからない場合、既存の正解を探すのではなく、自分の前提や脅威モデルに合わせて 新しい手法を組み立てる ことが求められる可能性があります。仕組みは公開されていても安全であるべき(いわゆる Kerckhoffs の原則)は暗号理論・標準化アルゴリズムの話で、実装・運用レベルでは別です。
曖昧さ回避版:https://dev.to/uni928/practical-baseline-safeguards-for-chatgpt-powered-services-efd
良い内容のネット記事の URL を、今後は下記に載せていきたいと思います。
3 Rotate Keys Regularly が優秀(従業員が退職した場合というのが最も重要です)
https://dev.to/alixd/api-key-security-best-practices-for-2026-1n5d