Aller au contenu principal
友田 陽大
Running the app you built with AI
バイブコーディング
AI駆動開発
セキュリティ
個人開発
Next.js

AIで作ったアプリを公開する前に — 非エンジニアのための本番リリース全ガイド

Claude Code・Cursor・Lovable・v0・Bolt でアプリを作ったけれど、公開して大丈夫か分からない。そんな非エンジニアの方に向けて、公開前に確認すべきことを「危険な順」に並べました。専門用語はすべて日常語に言い換え、各項目に自分で直す手順とAIに貼れる修正指示を添えています。

Published
Reading time
19 min read
Author
友田 陽大
Partager

「動いてる。でも、このまま公開していいのか分からない」

Claude Code や Cursor、Lovable でアプリを作った方から、いちばんよく聞く言葉です。この不安は正しい直感です。ただし、その理由はたぶんあなたが思っているものとは違います。

問題は「AIが書いたコードだから信用できない」ことではありません。AIは頼まれた機能は実装するが、頼まれていない防御は実装しない——これだけです。そして初めてアプリを作る人は、何を頼めばいいのかを知らない。当たり前です。知っていたら最初から自分で書けています。

この記事は、その「頼み忘れる部分」を危険な順に並べたものです。専門用語は初出時にすべて日常語に言い換えます。各項目には、自分で確認する方法と、そのまま Claude Code や Cursor に貼れる修正指示を添えました。

先に結論から言うと、公開前に必ず潰すべき項目は 4つ です。それ以外は、あとからでも間に合います。

この記事の内容を20問の質問形式にした無料セルフ診断があります。登録不要・入力内容はブラウザの外に出ません。読む前に自分の状態を知りたい方はそちらから。


1. なぜ「動く」と「安全」がずれるのか — 構造の話

まず、これがあなただけの問題ではないことを、測定結果で確認しておきます。

Veracode が100を超える大規模言語モデルを対象に80のコーディング課題で検証したところ、45%のケースで OWASP Top 10 に該当する脆弱性が混入していました。特にクロスサイトスクリプティング(他人が仕込んだスクリプトが自分のサイトで動いてしまう攻撃)への防御は、86%のサンプルで失敗しています。

GitGuardian の2026年の調査では、AIの支援を受けて書かれたコミットは、人間だけのコミットに比べて約2倍の頻度でAPIキーやパスワードを漏らしていました

これはモデルが賢くなれば消える種類の問題ではありません。理由はシンプルで、AIは「動作するか」を目標にしていて、「攻撃されるか」を目標にしていないからです。

料理に例えるなら、AIは「美味しい料理を作る」ことには非常に長けていますが、「食中毒を出さない」ことは、そう言われない限り気にしません。そして食中毒は、味見では分かりません。

「動く」の反対は「壊れている」ではない

初めて開発する方が誤解しやすいのはここです。

  • 動く / 動かない は、自分で試せば分かります
  • 安全 / 危険 は、試しても分かりません

たとえば「他人のデータが見えてしまう」状態のアプリは、あなたが自分のアカウントで使っている限り、完璧に正常に動きます。壊れて見えることは一度もありません。誰かがURLの数字を1つ書き換えるまでは。

だから公開前に、意図的に「悪いこと」を試す 必要があります。それがこの記事の中身です。


2. 危険度の順序 — 何から潰すか

やるべきことを全部並べると心が折れるので、順番を固定します。判断基準は「起きたときに取り返しがつくか」です。

順位項目起きること取り返し
1データベースの権限(RLS)が無い全ユーザーの全データが誰でも読み書きできるつかない(漏れたデータは戻らない)
2秘密の鍵がブラウザ側に出ている同上+データの削除・改ざんもできるつかない
3サーバー側の所有者チェックが無いURLの数字を変えると他人のデータが見えるつかない
4決済の二重処理を防いでいない顧客が二重に課金される/商品が二重に付与される返金はできるが信用は戻らない
5法務(個人情報・特商法)の不備法令違反、決済審査に通らない是正できる
6従量課金の上限が無い想定外の請求が届く交渉次第、痛い
7バックアップ・復旧手段が無い壊れたとき戻せない事前準備だけが対策
8エラーに気づけない壊れたまま何ヶ月も放置される気づけば直せる

1〜4 が「公開前に必ず」の4項目です。5〜8 は公開直後にやれば間に合います。

以降、この順に見ていきます。


3. 【最優先】データベースの権限 — RLS とは何か

何の話か

RLS(Row Level Security、行レベルセキュリティ)は「データベース側で、誰がどの行を見られるかを決める設定」です。

「行」というのは、表計算ソフトの1行だと思ってください。ユーザーの一覧表があったとして、Aさんは自分の行だけ、Bさんは自分の行だけ見られるようにする——それがRLSです。

なぜ致命的なのか

Supabase のようなサービスでは、ブラウザから直接データベースに問い合わせが飛びます。このとき使われる anon(匿名)キーは、設計上公開されているものです。ブラウザの開発者ツールを開けば誰でも読めますし、それは正常な状態です。

問題は、RLS が無効だと、その公開キーだけで全データが読み書きできてしまうことです。

つまりこうなります。

  1. 攻撃者があなたのアプリを開く
  2. 開発者ツールでデータベースのURLと anon キーを読む(どちらも公開情報)
  3. そのままデータベースに問い合わせる
  4. 全ユーザーの、全テーブルが返ってくる

ログイン画面があっても関係ありません。ログイン画面はブラウザ側の話で、データベースはそれを知らないからです。

これは実際に起きている

CVE-2025-48757 として登録されている脆弱性の説明は、こうです。

生成されたサイトのデータベースの行レベルセキュリティポリシーが不十分で、認証されていない遠隔の攻撃者が任意のデータベーステーブルを読み書きできる

深刻度は CVSS 9.3 CRITICAL。最も高い部類です。対象は AI アプリビルダーの Lovable でした。

ここで重要なのは、この CVE にベンダーから異議が出ていることと、その理由です。ベンダー側の主張は「アプリのデータ保護は利用者の責任である」というものでした。

つまり——あなたが作ったアプリのデータを守る責任は、あなたにあると公式に言われている、ということです。ツール側が守ってくれることを期待してはいけません。

確認のしかた

Supabase を使っている場合:

  1. Supabase の管理画面 → Table Editor を開く
  2. テーブル一覧に「RLS disabled」「Unrestricted」といった警告が出ていないか見る
  3. 出ていたら、それが全公開のテーブルです

RLS が有効でも安心できません。ポリシー(許可の条件)が USING (true) になっていると、「全員が全行を見られる」という意味なので、無効なのと同じです。

AIに貼る修正指示

Supabase のマイグレーション/SQL を全部読んで、次を表にして報告してください。
(1) RLS が有効になっていないテーブル
(2) RLS は有効だがポリシーが1つも無いテーブル
(3) ポリシーの条件が USING (true) など実質的に全員を許可しているテーブル

そのうえで、各テーブルについて「ログインした本人の行だけ」に絞る RLS
ポリシーの SQL を書いてください。性能のため auth.uid() は
(select auth.uid()) の形で書いてください。

最後の (select auth.uid()) は性能上の定石です。この形にしないと、行数が増えたときにデータベースが極端に遅くなることがあります。

より詳しくは Supabase の「RLS」って何? — AIが作ったアプリでデータが全公開になる仕組み で解説しています。書いたポリシーが本当に絞れているかは、無料のRLSチェッカーに貼り付けると判定できます。


4. 【最優先】秘密の鍵 — なぜ「APIキー」が他人に見えるのか

何の話か

アプリは外部サービス(データベース、決済、AI)を使うために「鍵」を持っています。この鍵の置き場所を間違えると、鍵ごと他人に渡ることになります。

いちばん多い間違いが、NEXT_PUBLIC_ を付けてはいけない値に付けてしまうことです。

Next.js では、環境変数(設定値)の名前が NEXT_PUBLIC_ で始まると、ビルド時にブラウザ向けのファイルへそのまま埋め込まれます。これは公式ドキュメントに明記された仕様であって、バグではありません。ブラウザで動かす必要がある値のための仕組みです。

問題は、AI が「動かすため」に、秘密の鍵にもこの接頭辞を付けてしまうことがある点です。付ければ確かに動きます。そして誰でも読めるようになります。

特に危険な鍵

Supabase には2種類の鍵があります。

  • anon キー — 公開前提。RLS の制限を受ける。ブラウザに置いてよい
  • service_role キーすべての制限を無視できる鍵。RLS を素通りする。絶対にブラウザに置いてはいけない

service_role キーが漏れると、RLS を正しく設定していても意味がありません。全部素通りされます。AI が生成したコードでこの鍵が使われがちなのは、「とりあえず動く」からです。RLS ポリシーを書かなくてもデータが取れるので、エラーが出ません。

確認のしかた

  1. プロジェクト内を NEXT_PUBLIC_ で検索する
  2. 出てきた値のうち、「これが他人に見えても平気か?」を1つずつ考える
  3. 少しでも迷ったら、それは移動すべき値です

あわせて、GitHub にコードを上げている場合は .env ファイルがコミットされていないか確認してください。一度コミットした鍵は、あとからファイルを消しても履歴に残ります。消すだけでは対策になりません。鍵そのものを作り直す必要があります。

AIに貼る修正指示

このプロジェクト全体を調べて、NEXT_PUBLIC_ が付いた環境変数に秘密情報
(Supabase の service_role キー、データベースのパスワード、各種 API の
秘密鍵)が入っていないか確認してください。

見つかった場合は、その値をサーバー専用の環境変数に移し、参照している
コードをサーバー側(Route Handler / Server Action)に移動してください。
クライアントコンポーネントから秘密情報を参照している箇所があれば、
すべて一覧にして報告してください。

なお、値そのものは出力せず「どのファイルの何行目にどの種類の鍵があるか」
だけを報告してください。

詳細は NEXT_PUBLIC_service_role — AIが書いた「APIキー」がなぜ他人に見えるのか にまとめました。


5. 【最優先】所有者チェック — 「ログインしてる風」と本物の権限

何の話か

これは説明しづらいのですが、いちばん見落とされる項目です。

あなたのアプリに /orders/123 のような画面があるとします。123 は注文番号です。ここで、URLの 123 を 124 に書き換えたら何が起きるか

もし他人の注文が表示されたら、それが脆弱性です。OWASP(Webセキュリティの標準的な団体)がAPIリスクの第1位に挙げている、最も一般的な穴です。

なぜ起きるのか

画面上に他人へのリンクが出ていなければ安全、と考えてしまうからです。しかしURLを直接打てば、リクエストは飛びます。リンクの有無は関係ありません。

AI は「ログイン中のユーザーの注文一覧を表示する」と頼まれれば、一覧はきちんと絞り込みます。しかし「注文詳細を表示する」と頼まれると、番号で引いてくるだけのコードを書きがちです。一覧が正しく絞られているので、動作確認では絶対に気づきません。

確認のしかた

これはブラウザだけで確認できます。

  1. テスト用のアカウントを2つ作る(AさんとBさん)
  2. Aさんでログインし、何かデータを作る。URLの番号(またはID)を控える
  3. ログアウトして、Bさんでログインする
  4. 控えたURLをアドレスバーに直接打ち込む

Bさんに、Aさんのデータが見えたらアウトです。見えずにエラーや「権限がありません」になれば正常です。

これは同じアプリの中で誰でもできる確認なので、公開前に必ず1回やってください。

AIに貼る修正指示

このアプリの、IDを受け取ってデータを返す/更新するすべての処理
(Route Handler、Server Action、API)を洗い出して、サーバー側で
「そのデータがログイン中のユーザーのものか」を検証しているか
1つずつ確認してください。

検証していないものがあれば、所有者チェックを追加した実装に修正して
ください。フロントエンドで表示を隠しているだけの箇所も、防御に
なっていない箇所として報告してください。

RLS を正しく設定していれば、この防御は二重になります。逆に言えば、RLS とサーバー側チェックはどちらか一方ではなく両方あるのが正しい状態です。

AIが作ったログイン機能は本物か — 「ログインしてる風」と本物の認可の違い で、実例を交えて詳しく扱っています。


6. 【最優先】決済 — 二重課金はなぜ起きるか

決済機能が無いアプリなら、この章は飛ばして構いません。

何の話か

Stripe をはじめとする決済サービスは、支払いが完了すると、あなたのアプリに「支払われましたよ」という通知(Webhook と呼びます)を送ります。あなたのアプリはそれを受けて、商品を渡したり、残高を増やしたりします。

ここに落とし穴があります。この通知は「最低1回」届く仕組みで、同じ通知が複数回届くことがあります。ネットワークが不安定だったり、あなたのアプリの応答が遅れたりすると、決済サービスは「届かなかったかもしれない」と判断して再送します。これは仕様であり、Stripe の公式ドキュメントにも明記されています。

通知を受け取るたびに残高を足す実装だと、そのまま二重付与になります。

なぜAIは書き漏らすのか

「支払いが完了したら残高を増やす」と頼めば、AI はその通りに書きます。それは正しい実装です。ただし「同じ通知が2回来たらどうするか」は、頼まれていないので考慮されません。

そしてこの不具合は、テストでは絶対に出ません。手元では通知は1回しか来ないからです。本番で、しかも忙しい時間帯に初めて出ます。

対策 — 冪等性(べきとうせい)

対策には名前があります。冪等性——「何回やっても結果が同じになる性質」のことです。

具体的には、通知に含まれるイベントIDをデータベースに保存し、すでに処理済みのIDが来たら何もせず「受け取りました」と返すだけです。難しくはありません。忘れられるだけです。

私が担当した決済基盤では、この設計により本番での二重課金を0件に保っています。技術的に難しい話ではなく、「必ずやる」と決めているかどうかの差です。

AIに貼る修正指示

このアプリの決済 Webhook の処理を読んで、同じイベントが複数回届いた
ときに二重処理されないか確認してください。

イベントIDを一意キーとして保存し、処理済みなら早期リターンする
冪等性の実装を追加してください。記録と業務処理は同一トランザクションに
まとめ、失敗時に決済サービスが再送できるよう適切なステータスコードを
返す実装にしてください。

あわせて、(1) 金額がクライアントから送られた値を使っていないか、
(2) Webhook の署名検証が行われているか、も確認してください。

AIに決済を作らせたとき、二重課金が起きる理由と防ぎ方 で、金額の改ざんと署名検証まで含めて扱っています。


7. 静かに間違うコード — 動くのに正しくない

ここからは「公開前に必ず」ではありませんが、放置すると効いてくる項目です。

AI 生成コードで最も多い不具合は、実は脆弱性ではありません。エラー処理と業務ロジックの間違いです。そしてこれらが厄介なのは、エラーが出ないことです。

  • 集計が微妙に合わない(境界の日付が含まれていない)
  • 検索結果が一部欠ける(並び順が不定で、ページ送りで漏れる)
  • 失敗したのに成功と表示される(例外を握りつぶしている)

どれも画面上は正常に動きます。数字が少し違うだけです。だから何ヶ月も気づかれません。

対策は「壊れてはいけない条件」を先に言語化することです。「合計は必ず明細の和と一致する」「同じ検索を2回したら同じ順序で返る」——こういう当たり前のことを書き出して、AIにテストとして書かせます。

「動いてるのに間違ってる」— AI生成コードで一番多い静かなバグ で扱っています。


8. お金と法律 — 見落としやすい2つ

従量課金

クラウドサービスやAIのAPIは、使った分だけ請求されます。想定外のアクセスや無限ループがあると、請求は簡単に跳ねます。個人開発で数十万円の請求が届く事故は珍しくありません。

公開直後にやるべきは3つです。各サービスの請求アラート設定、AI APIのキー単位の上限額設定、そしてアプリ側のレート制限(同じ人からの連続リクエストを制限する仕組み)。

公開したら請求が跳ねた — 従量課金の事故と上限設定

法務

メールアドレスを1つでも預かるなら、プライバシーポリシーの掲載は個人情報保護法上の義務です。「個人だから」「無料だから」は免除の理由になりません。

有料で提供するなら、特定商取引法に基づく表記も必要です。事業者名・連絡先・価格・支払時期・返品条件などの表示が法律で決まっています。Stripe の審査でも、ここが整っていないと通らないことがあります。

個人情報・特商法・プライバシーポリシー — AIアプリを商用公開する前の法務チェック


9. 壊れたときに戻れるか — 運用の最低ライン

最後は、公開後に効いてくる3点です。

バックアップ。 AI に「このテーブルを整理して」と頼んだ結果、意図せずデータが消えることがあります。無料プランはバックアップの保持期間が短い、あるいは自動バックアップが無いこともあります。「気づいたときには復旧できる期間を過ぎていた」が起こります。

ロールバック。 デプロイして壊れたとき、前のバージョンに戻す手順を知っていますか。深夜に本番が落ちたまま何時間も復旧できない、という事態は、手順を一度試しておくだけで防げます。なお、データベースの構造変更はコードと違って自動では戻りません。

エラーの可視化。 個人開発で最も多いのは「壊れていることに気づかない」です。フォームが送信できない状態が何ヶ月も続く——実際に起こります。ブラウザ側だけで失敗しているエラーは、サーバーのログには残りません。無料枠のあるエラー監視サービスを1つ入れておくだけで、状況は大きく変わります。

引き継ぎまで見据えるなら エンジニアに相談・引き継ぐときの準備 もどうぞ。


10. 公開前チェックリスト(印刷用)

上から順に、1つずつ。

公開前に必ず

  • 全テーブルで RLS が有効で、ポリシーが「本人の行だけ」に絞られている
  • 書き込み(INSERT/UPDATE)にも制限がかかっている(WITH CHECK
  • service_role キーやDBパスワードが NEXT_PUBLIC_ に入っていない
  • .env が GitHub にコミットされていない
  • 一度でも人目に触れた鍵を作り直した
  • 別アカウントでURLの番号を書き換えて、他人のデータが見えないことを確認した
  • 管理者機能がサーバー側で権限確認されている
  • (決済がある場合)Webhook が二重に届いても二重処理されない
  • (決済がある場合)金額をサーバー側で決めている
  • (決済がある場合)Webhook の署名を検証している

公開直後に

  • プライバシーポリシーを掲載した
  • (有料の場合)特定商取引法に基づく表記を掲載した
  • 各サービスの請求アラート・上限を設定した
  • バックアップの有無と保持期間を確認した
  • 前のバージョンに戻す手順を1回試した
  • エラー監視を入れた、または重要処理の失敗が自分に届くようにした
  • 本番URLで、登録とパスワード再設定が実際に動くことを確認した

このチェックリストを20問の質問形式にして、危険な順に並べた結果とAIへの修正指示を出す無料セルフ診断を用意しています。登録不要・約5分です。


まとめ — 作ったこと自体は、何も間違っていない

最後に一つだけ。

生成AIでアプリを作ったこと自体は、まったく正しい選択です。私自身、日々 Claude Code で本番のプロダクトを書いています。速くて安いのは事実で、それを使わない理由はありません。

ただ、「速く作る」と「安全に出す」は別の作業です。前者はAIが劇的に上手くなりました。後者は、まだ人間側に残っています。

そして後者は、思っているより短時間で終わります。この記事の4項目——RLS、鍵の露出、所有者チェック、決済の冪等性——を潰すだけで、致命的な事故のほとんどは防げます。全部作り直す必要はありません。

分からない項目があったら、まずは各章の修正指示をAIに貼ってみてください。それでも判断がつかないところ(特に認可の設計、決済、個人情報の扱い)だけ、人に聞けば十分です。

Questions fréquentes

コードが読めなくても、公開前に自分で確認できますか?
できます。この記事の確認項目は、コードではなく「アプリがどう振る舞うか」を見る形にしてあります。たとえば「URLの番号を他人の番号に書き換えたら、他人のデータが見えてしまうか」は、ブラウザだけで確かめられます。判断がつかない項目は、記事内の修正指示をそのまま Claude Code や Cursor に貼れば、AIが現状を調べて報告してくれます。
AIで作ったアプリは、そもそも公開すべきではないのですか?
そんなことはありません。危ないのは「AIで作ったこと」ではなく「動いたところで検証を止めること」です。AIは指示された機能は実装しますが、不正な入力・同時アクセス・権限のすり抜けといった敵対的な条件は、明示しない限り考慮しません。逆に言えば、その部分だけ人間が埋めれば公開して問題ありません。
公開前に絶対に潰すべき項目はどれですか?
4つです。(1) データベースの行レベルセキュリティ(RLS)が有効で本人の行だけに絞られていること、(2) service_role キーなどの秘密の鍵がブラウザ側に出ていないこと、(3) サーバー側で「そのデータがログイン中の本人のものか」を検証していること、(4) 決済の通知が二重に届いても二重に課金・付与されないこと。この4つは程度問題ではなく、あるかないかの問題です。
すでに公開してユーザーがいます。今からでも間に合いますか?
間に合います。むしろ実ユーザーがいる場合は、全部止めるのではなく優先順位をつけて順番に塞ぐほうが現実的です。最初にやるのは「今すぐ止めるべきものがあるか」の判定で、具体的には秘密の鍵の漏洩と、他人のデータが見える状態の2つ。この2つが無ければ、サービスを動かしたまま順に対応できます。
全部の項目を自分で直す必要がありますか?
ありません。多くの項目は、記事内の修正指示をAIに貼れば自力で直せます。判断が分かれるのは「認可の設計」「決済」「個人情報の扱い」の3領域で、ここはAIに聞いても正解が一つに決まらないため、人の目を入れる価値があります。それ以外は自分で進めて構いません。

Références

友田

友田 陽大

Créateur d’un produit lauréat du prix du ministre (METI). Avec TypeScript + Python + AWS, je livre SaaS, transformation numérique industrielle et IA générative (RAG) prête pour la production — des spécifications à l’infrastructure et à l’exploitation, seul.

“It works. But is it safe to launch?”

Twenty questions, no signup — a pre-launch self-check for the app you built with AI

You don't need to read any code. Answer yes / no / not sure to questions like “can only the person who logged in see their own data?” You get your risks ordered by severity, plus a fix instruction you can paste straight into Claude Code or Cursor. Nothing you type leaves your browser.

Disponible en mission au forfait comme en conseil technique. Commencez par un échange gratuit de 30 minutes.

最短ルート:カレンダーから直接予約

相談内容が固まっている方は、フォーム送信よりその場で日程を確定する方がスムーズです。下記から空き時間をお選びください。

  • 30分のオンライン無料相談
  • Google Meet / Zoom / Microsoft Teams
  • NDA 商談前締結可・無理な営業はいたしません
無料相談の空き枠を予約する

À lire également