結論から
AIで作ったアプリを公開する前に、エンジニアに頼まなくても自分でできるチェックは5つあります。どれもブラウザだけで、1つ5分。合計30分で、実際に起きた事故(Moltbook、Lovable 製アプリの CVE、RedAccess の5,000本)の入口の大半を、自分で先に見つけられます。
この記事は、これまでの5本の総集編です。5つの手順を1ページにまとめ、動画も1本(約12分)にしました。
- URLの数字を1つ変える → 他人のデータが見えたら、サーバーが本人確認をしていない
- F12で「sk-」「service_role」を検索 → 出てきたら、キーが全員に見えている
- シークレットウィンドウで /admin を開く → 開けたら、管理画面が全員に公開されている
- URLの金額・数量を書き換える → 通ったら、サーバーが画面の値を信じている
- ログアウトして画像URLを直接開く → 表示されたら、ファイルが全員に公開されている
5つに共通する一文は、「決めるのはサーバー側。画面とURLは信じない」です。
準備するもの(5分)
- Chrome の シークレットウィンドウ(Mac: ⌘⇧N / Windows: Ctrl+Shift+N)。「ログインしていない誰か」になれます
- テスト用アカウント2つ(Aさん・Bさん。ダミーのメールで)
- 公開URL(ローカルではなく、実際に使うURL)
- 結果をメモする場所。各項目を ◯(合格)/✗(未対策)/?(分からない) で
チェック①:URLの数字を1つ変える(5分)
手順:Aさんでログイン → 自分の予約・注文・プロフィールのページを開く → URLの /reservations/12 ?id=12 の数字を 13 に変えて Enter。
- 他人のデータが表示された → ✗
- 「表示できません」「見つかりません」 → ◯
なぜ:サーバーが「13番はログイン中の本人のものか」を確かめず、頼まれた番号をそのまま返しています。リンクを出していなくても、URLは誰でも打てます。
AIへの一文:「IDで取得するすべての処理で、そのデータがログイン中のユーザーのものかをサーバー側で確認して。他人なら403。」(→ 詳しくは「URLの数字を1つ変えてみる」)
チェック②:F12でキーを検索する(3分)
手順:公開URLを開く → F12 → Sources タブ → ⌘⇧F(Ctrl+Shift+F)で全文検索 → 「sk-」「service_role」「eyJ」。
- 出てきた → ✗。そのキーは、アプリを開いた全員のブラウザに配られています
- 0件 → ◯
なぜ:AIは動作確認が早いので、まずフロントにキーを書きます。フロントに書いたものは「表示していない」だけで「隠せている」ではありません。
AIへの一文:「フロントに含まれるAPIキーをすべて列挙して、サーバー側の環境変数に移し、フロントからはサーバー経由で呼ぶように書き換えて。」そして古いキーは無効化して再発行。(→「AIはAPIキーをまずフロントに書く」/漏れたあとは「キーが漏れた瞬間の30分」)
チェック③:シークレットウィンドウで /admin を開く(3分)
手順:シークレットウィンドウで アプリのURL/admin を開く。ついでに /dashboard /manage /users も。
- 管理画面が表示された → ✗
- ログイン画面に飛ばされた → ◯。さらにAさん(一般ユーザー)でログインして開き、403なら ◯
なぜ:「リンクを置いていない」は守っていません。サーバーが「ログインしているか」「管理者か」を確かめていないだけです。
AIへの一文:「管理画面と管理用APIすべてに、サーバー側でログイン済みか・管理者かを確認する処理を入れて。未ログインはログイン画面へ、管理者以外は403。」(→「シークレットウィンドウで /admin を開く」)
チェック④:URLの金額・数量を書き換える(5分)
手順:お会計・注文確認のページで、URLやフォームに price=12800 qty=1 のような値が無いか見る → price=1 に書き換えて開く。フォームなら F12 → Elements で hidden の値を書き換えて送信。
- 「¥1」で確定できた → ✗
- 定価のまま、または拒否された → ◯
なぜ:画面側のチェックは、送る側が書き換えられます。「入力チェックを入れて」と頼むと、AIは画面側に書きます。決めるのはサーバー側。
AIへの一文:「金額は画面の値を使わず、サーバー側で定価から再計算して。数量・権限・入力もサーバー側で検証して、画面側だけで済ませないで。」(→「サーバー側で検証して」の一言)
チェック⑤:ログアウトして画像URLを直接開く(3分)
手順:ログイン中に、アップロードした画像・PDF を右クリック →「アドレスをコピー」→ シークレットウィンドウで開く。
- 表示された → ✗。ページの鍵と、ファイルの鍵は別です
- 「ログインが必要」「403」「Not found」 → ◯
なぜ:画像やPDFは、ページとは別の置き場(ストレージ)から直接配られます。AIは「画像を表示して」に対して、いちばん簡単な「公開バケット」を選びます。
AIへの一文:「個人に紐づくファイルを非公開バケットに移して、パスは user_id で始め、本人だけが読めるポリシーに。表示はサーバー側で本人確認してから期限付きの署名付きURLで。」(→「ログアウトして画像URLを直接開く」)
結果の読み方
- ✗が1つでもあれば、公開前に直す。どれも「他人のデータが見える」「キーが漏れる」に直結します
- ◯が5つでも、終わりではない。これは「自分で見つけられる10項目」の半分。コードを読まないと分からない残り(管理APIの権限、Git履歴のキー、サーバー側の検証、バックアップ、依存パッケージ…)は、エンジニアに頼みます
- 頼むときは、この5つの◯✗メモと、「頼む前に用意する5つ」(公開URL・コード・テスト用アカウント・一文とデータ・外部サービス)を添えてください。返事が「いつ空いていますか」から「ここが危ない、概算は〜」に変わります
Supabase を使っているなら、もう1つ
Table Editor で赤い「RLS disabled」が無いか。緑でもポリシーが USING (true) なら全員に公開です。AIは動かすために RLS を切り、動いた瞬間に戻す理由が消えます。(→「AIはRLSを切って開発し、戻さない」/「Moltbook」)
よくある質問
5つ全部やる時間がありません。どれからですか。
①と③です。この2つで、実際の事故の入口(他人のデータ・管理画面)の多くが分かります。次に②(キー)。④⑤は、決済とアップロード機能がある場合に。
◯だったのに、あとで漏れました。
機能を追加するたびに、AIは同じ順番で作業します。5つのチェックは公開前に1回ではなく、機能を足すたびにやり直してください。30分です。
エンジニアに全部任せたほうが早くないですか。
この5つは、エンジニアが最初の30分にやることと同じです。先にやっておくと、その30分がコードの中を見る時間に使われます。費用も返事の速さも変わります。


