AIで作ったWebアプリを公開する前に、確認しておきたいことを42項目のチェックリストにまとめました。
セキュリティ、公開の準備、規約と個人情報、運用の準備の4つに分けています。
Next.js、Vercel、Supabase、Firebase、Stripe を使ったアプリを想定していますが、ほかの構成でも考え方はそのまま使えます。
Who am I?
BPR Prot. は、AIで作ったアプリ・Webサービスのローンチ前の最終確認から、公開後の見守りまでを、ひとつのツールで伴走するサービスです。個人開発に励む皆さんが安心してサービスを公開できるように、日々セキュリティまわりの情報を追いかけています。
X(@BPR_Prot)では、セキュリティの最新情報やリリース前に見落としやすいポイント、Claude Code などのAI活用Tipsを日々発信しています。よければご覧ください!
チェックリストの使い方
すべての項目を一度で完璧にする必要はありません。
★の付いた10項目は、公開前に必ず見てほしいものです。まずはここから始めて、使っていない機能の項目は飛ばしてください。

★の多くは、鍵の管理とデータの権限に関する項目です。
Webアプリを公開すると、まだ誰にも知らせていなくても、自動で動くプログラムからのアクセスがすぐに届き始めます。
よくあるのは、/.env や /.git/ のような、うっかり公開されがちなファイルを片っ端から探しにくるものです。
サービスの規模や知名度は関係ないので、鍵が外に出ていないか、他人のデータを見られる状態になっていないかは、公開前に必ず押さえておきたいところです。
AIにコードを確認してもらうのも良いのですが、クラウドの管理画面の設定や本番環境の権限はAIからは見えていないことも多いので、自分の目で確認しておくことが重要です。
セキュリティ (1〜26)
公開前にチェックしておきたい項目が一番多いのがセキュリティ周りです。最初から満点を狙うとなかなか前に進まず手が止まってしまうので、★の付いた項目から順に見ていってください。
鍵やパスワードの置き場所
- ★
.envや鍵ファイルがリポジトリに入っていないか
git add . でまとめてコミットしたら、.env や秘密鍵、サービスアカウントのJSONまで入っていた、というのはよくある事故です。.gitignore にあとから書き足しても、すでにgitが追跡しているファイルは対象から外れません。
次のコマンドで、それらしいファイルが追跡されていないか確認できます。
git ls-files | grep -iE '(^|/)\.env|\.pem$|\.p12$|service-account.*\.json$'
一度でもpushした鍵が見つかったら、ファイルを消すだけでは足りません。発行元でその鍵を無効にして、新しい鍵に差し替えてください。
2. ★ NEXT_PUBLIC_ の付いた変数に秘密が入っていないか
Next.jsでは、NEXT_PUBLIC_ で始まる環境変数はブラウザ用のJavaScriptに埋め込まれます。「クライアント側で環境変数が読めない」というエラーをAIに直してもらうと、この接頭辞を付けるだけで解決していることがあります。エラーが消えたら、その変数に秘密の値が入っていないか一度見直しておくと安心です。
ブラウザに出してよいのは、Supabaseのanonキーのように、公開される前提で作られた値だけです。秘密の鍵を使う処理は、サーバー側に置きましょう。
3. ★ gitの履歴に鍵が残っていないか
今のファイルから消しても、過去のコミットには鍵が残っています。リポジトリを公開するつもりなら、履歴までさかのぼって検索しておくのが安全です。鍵が見つかったら、履歴を書き換えるより先に、その鍵を無効にしてください。履歴を書き換えても、すでに誰かが複製したものまでは消せないからです。
データベースの権限
4. ★ Supabaseの全テーブルでRLSとポリシーが設定されているか
Supabaseでは、RLS(行単位のアクセス制御)を有効にしてはじめて、行ごとに「誰が読めるか」を決められます。有効にしただけだと自分のデータまで読めなくなるので、ポリシーもセットで書く必要があります。
service_role キーはRLSを素通りするので、ブラウザには絶対に渡さないでください。また、画面にデータが出ないエラーをAIに直してもらったら、RLSを無効にして解決していた、ということもあります。一度テーブルの設定画面を開いて確かめておくと安心です。
5. ★ FirebaseのSecurity Rulesが全開放になっていないか
開発中に allow read, write: if true; や期限付きの全開放ルールにして、そのまま戻し忘れているケースは少なくありません。Firestoreだけでなく、Storageのルールも同じように見ておきます。
サーバーで使うAdmin SDKは、Security Rulesを通りません。そのため、サーバー側の処理では、リクエストしてきたのが誰で、その操作をしてよい人なのかを、自分のコードで確かめる必要があります。
6. ★ 他人のIDを指定してもデータが見えないか
URLやリクエストに含まれる userId や orderId を別の値に書き換えて、他人のデータが返ってこないか試してみてください。クライアントから送られてきたIDはそのまま信用せず、ログイン中のユーザーがそのデータの持ち主かどうかを、サーバー側で確かめます。
ログインと権限
7. ログインしただけで管理画面や他人のデータを操作できないか
一般ユーザーのアカウントでログインして、管理画面を開いたり、他人の投稿を編集したりできないか試してみます。「ログインしているかどうか」だけを見ていて、「その操作をしてよい人か」を見ていないと、ここで通ってしまいます。
8. セッションCookieの属性を確認したか
自分でセッションCookieを発行している場合は、ログイン状態を保存しているCookieに Secure・HttpOnly・SameSite が付いているかを見ます。ブラウザの開発者ツールでCookieの一覧を開けば、すぐに分かります。
9. パスワードリセット後に古いリンクやセッションが残らないか
パスワード再設定のリンクが2回使えてしまわないか、リンクの一部を書き換えると他人のパスワードまで変えられてしまわないかを試してみます。あわせて、パスワードを変えたときに、ほかの端末のログインを解除するかどうかも決めておきましょう。
入力の扱い
10. 画面に表示する入力値をHTMLとして差し込んでいないか
プロフィールや投稿欄に入力された文字を、HTMLとしてそのまま画面に埋め込むと、中に仕込まれたスクリプトまで実行されてしまいます(XSS)。Reactなら、dangerouslySetInnerHTML を使っている箇所を探すのが近道です。
11. SQLを文字列の連結で作っていないか
検索語やIDを、文字列の足し算でSQLに埋め込んでいる箇所がないか探します。ライブラリのプレースホルダー(? や $1)を使えば、入力された値がSQLの命令として実行されることはありません。
12. アップロードできるファイルの種類と保存先を決めているか
アップロード機能があるなら、受け付けるファイルの種類とサイズの上限を決めておきます。種類は拡張子だけで判断しないこと、アップロードされたファイルをサーバー上で実行できる場所に置かないことも大切です。
HTTPSとセキュリティヘッダ
13. http:// で開いたときに https:// へ転送されるか
トップページだけでなく、ログイン画面や管理画面、コールバックURLも、http:// を付けて一度ずつ開いてみてください。独自ドメインに付け替えた直後は、古いURLやサブドメインが転送されずに残っていることがあります。
14. HSTSなどの基本ヘッダが付いているか
HSTSは「このサイトには今後HTTPSでつないでね」とブラウザに伝えるヘッダです。ほかにも、X-Frame-Options や X-Content-Type-Options など、基本的なヘッダが一通り付いているかも見ておきます。
15. CSPが付いているだけでなく、実際に効いているか
CSPは、読み込んでよいスクリプトの出どころをブラウザに伝えるヘッダです。付けたつもりでも、設定しだいでは画面が壊れたり、逆に何も制限できていなかったりします。主要な画面を開いて、表示が崩れていないか、開発者ツールのコンソールにCSPのエラーが出ていないかを見れば、おおよその状態が分かります。
いきなり強制するのではなく、まずは違反を記録するだけの Report-Only モードで様子を見てから切り替えると安全です。
外部からの呼び出し
16. CORSで許可する接続元を広げすぎていないか
CORSは、別のドメインからAPIを呼んでよいかを決める設定です。許可するのは、実際に呼び出す必要がある接続元だけで十分です。CORSのエラーを消すために *(すべて許可)にして、そのまま残っているケースはよくあります。
17. ログインやフォームにレート制限があるか
短時間に何度もリクエストを送られたときに、途中で止められるでしょうか。一度自分で連続して送ってみると、すぐに分かります。メール送信やAI APIにつながるフォームは、連打されるとそのまま費用がかさむので、早めに手を打っておきたいところです。
18. エラーメッセージに内部情報を出していないか
画面やAPIのレスポンスに、スタックトレースやSQL、ファイルのパスが出ていると、攻撃する側にヒントを与えてしまいます。詳しいエラーはサーバーのログで追えるようにしておき、画面には「うまくいきませんでした」程度の案内だけを出します。
19. ユーザー指定のURLをサーバーが無条件に取得していないか
URLを入力するとプレビューや要約を表示する機能があるなら、サーバーがアクセスしてよい宛先を決めておきます。社内ネットワークやクラウドの内部アドレスに向けたリクエストは、リダイレクト先も含めて止めてください。
依存パッケージ
20. 脆弱性が見つかっているパッケージを使い続けていないか
次のコマンドで、本番で使うパッケージだけに絞って脆弱性を調べられます。
npm audit --omit=dev
npm audit fix --force を使うとメジャーバージョンが上がることがあるので、更新したあとはビルドして、主要な画面が動くかまで見ておきます。
21. AIが提案したパッケージ名は実在するか
AIは、存在しないパッケージ名をそれらしく提案してくることがあります。見覚えのない名前が出てきたら、公式ドキュメントで同じ名前が紹介されているかを調べてからインストールすると安心です。
決済
決済機能がないアプリなら、この2項目は飛ばして構いません。
22. ★ Stripe Webhookの署名を検証しているか
WebhookのURLには、Stripe以外の誰でもリクエストを送れます。本当にStripeから届いたものかどうかは、署名を検証して確かめます。検証には受け取ったままの本文が必要なので、先にJSONに変換してしまうと失敗します。
23. ★ 同じ決済通知を二重に処理しないか
StripeのWebhookは、同じイベントが2回以上届くことがありますし、届く順番も決まっていません。処理したイベントIDを保存しておけば、同じ通知が来ても課金状態を二重に更新せずに済みます。
AI機能を組み込んでいる場合
24. プロンプトインジェクションを受けても被害が広がらないか
ユーザーの入力は、システム側の指示と混ぜずにAIへ渡します。それでも完全には防げないので、AIの出力は、決めた形式になっているかをチェックしてから使いましょう。出力をそのままHTMLやSQLとして実行すると、被害が一気に広がります。
25. 利用回数と課金額に上限があるか
1人あたりの利用回数に上限を設け、APIの提供元の管理画面で予算アラートも設定しておきます。ログインしなくても使える入力欄から、重い処理を何度でも呼び出せてしまわないかも要チェックです。
開発環境
26. MCPサーバーの出所と権限を把握しているか
開発に使っているMCPサーバーの中には、手元のファイルや外部サービスを操作できるものがあります。それぞれ誰が配布しているものか、渡したトークンの権限が広すぎないかを、一度書き出してみてください。
使っていないMCPサーバーは外し、設定ファイルに鍵を直接書き込まないようにします。公開するアプリだけでなく、それを作っている手元の開発環境も、見直しておきたい場所のひとつです。
公開の準備(27〜33)
このあたりは、本番のURLや実際のスマホで触ってみないと気づきにくいものばかりです。公開する環境で、まとめて試してみるのがおすすめです。
27. 独自ドメインとHTTPSが正しくつながっているか
www のあり・なしの両方でアクセスして、想定したURLにたどり着くか試します。ログインや決済のサービスに登録したコールバックURLを、本番用に切り替え忘れていないかも要チェックです。
28. 送ったメールが迷惑メールに入らないか
登録確認やパスワード再設定のメールを、実際に自分宛てに送ってみます。迷惑メールフォルダに入るようなら、メール配信サービスの管理画面で、送信ドメイン認証の設定を見直します。
29. タイトル、description、OGPを設定したか
検索結果に表示されるタイトルと説明文を、ページごとに設定しておきます。OGP(SNSでシェアしたときに出る画像と文章)は、自分でページを開いても確認できません。SNSやチャットに実際にURLを貼って、きちんと表示されるか試してください。
30. 404とエラー画面から戻れるか
存在しないURLをわざと開いてみてください。真っ白な画面や英語のエラーだけが出るなら要注意です。トップページに戻るリンクが1つあれば、それで十分です。
31. スマホで操作できるか
ブラウザの幅を縮めて確認するだけでなく、実際のスマホで、登録から主な操作までひと通り試してみます。ボタンが押しにくかったり、キーボードで入力欄が隠れてしまったりといった問題は、実機でないとなかなか気づけません。
32. アクセス解析が動いているか
アクセス解析のタグを入れたら、自分で実際にアクセスして、管理画面の数字が動くところまで確認しましょう。あわせて、プライバシーポリシーに書いた内容と、実際に集めている情報が食い違っていないかも見ておきます。
33. 表示の遅いページがないか
トップページだけでなく、画像の多いページやログイン後の画面も、本番環境で開いてみます。細かい数値を追い込むのは公開後でも大丈夫です。まずは「待たされる」と感じる画面から直していけば十分です。
規約と個人情報(34〜37)
規約やプライバシーポリシーに何を書くべきかは、サービスの内容によって変わります。迷ったときは、消費者庁などの公的な案内を読むか、専門家に相談してください。
34. ★ 利用規約とプライバシーポリシーがあるか
どちらも、ユーザーが登録する前に読める場所に置いておきます。書いてある「集める情報」と「使い道」が、実際のサービスと合っているかも確認します。AI機能で入力内容を外部のAPIに送っている場合は、そのことも書いておきましょう。
35. ★ 有料サービスに必要な表示があるか
有料で提供するなら、「特定商取引法に基づく表記」が必要かどうかを、消費者庁の案内で確認できます。表記に書いた価格や解約の条件は、実際の販売ページと食い違わないようにそろえます。
36. 取らなくてよい個人情報まで集めていないか
登録フォームとデータベースを見比べて、使っていない項目があれば削除しましょう。「いつか使うかも」と集めた個人情報も、持っている限りは管理しなければなりません。
37. 退会とデータ削除ができるか
退会ボタンが分かりやすい場所にあるか、退会したときにどのデータが消えるのかを、一度実際にたどってみます。問い合わせで退会を受け付ける場合は、その手順をどこかに書いておくと親切です。
運用の準備(38〜42)
公開したあとにトラブルが起きても、すぐに気づいて対応できるように、ログや通知の設定は公開前に済ませておくと安心です。
38. ログに個人情報や鍵を出していないか
デバッグ用の console.log が残っていないか、一度コード全体を検索してみましょう。画面には表示されないので、消し忘れても気づきにくいものです。リクエストの中身やトークン、パスワードをまるごとログに出していると、そのログ自体が情報漏えいの原因になります。
39. バックアップから戻せるか一度試したか
バックアップを取っていても、実際に戻せるかどうかは試してみないと分かりません。一度だけ別の環境に復元してみて、その手順をメモしておくと、いざというときに慌てずに済みます。
40. 障害に気づける仕組みがあるか
トップページや主要なAPIが止まったときに、自分に通知が届くようにしておきます。通知先が古いメールアドレスのままになっていることもあるので、テスト通知を1回送って確かめておくと確実です。
41. 問い合わせ窓口が見つかるか
不具合や退会の連絡を受ける窓口を用意して、フッターなどから見つけられるようにしておきます。返信できないアドレスしか載っていない、という状態は避けたいところです。
42. クラウドとAPIの利用料金に上限や通知があるか
ホスティングやデータベース、メール配信、AI APIの管理画面を、一通り開いてみます。予算の上限を設定できるサービスは設定し、できないものは利用量のアラートだけでも入れておきましょう。
コピーして使えるチェックリスト
セキュリティ
-
1. ★
.envや鍵ファイルがリポジトリに入っていないか -
2. ★
NEXT_PUBLIC_の付いた変数に秘密が入っていないか - 3. ★ gitの履歴に鍵が残っていないか
- 4. ★ Supabaseの全テーブルでRLSとポリシーが設定されているか
- 5. ★ FirebaseのSecurity Rulesが全開放になっていないか
- 6. ★ 他人のIDを指定してもデータが見えないか
- 7. ログインしただけで管理画面や他人のデータを操作できないか
- 8. セッションCookieの属性を確認したか
- 9. パスワードリセット後に古いリンクやセッションが残らないか
- 10. 画面に表示する入力値をHTMLとして差し込んでいないか
- 11. SQLを文字列の連結で作っていないか
- 12. アップロードできるファイルの種類と保存先を決めているか
- 13. http:// で開いたときに https:// へ転送されるか
- 14. HSTSなどの基本ヘッダが付いているか
- 15. CSPが付いているだけでなく、実際に効いているか
- 16. CORSで許可する接続元を広げすぎていないか
- 17. ログインやフォームにレート制限があるか
- 18. エラーメッセージに内部情報を出していないか
- 19. ユーザー指定のURLをサーバーが無条件に取得していないか
- 20. 脆弱性が見つかっているパッケージを使い続けていないか
- 21. AIが提案したパッケージ名は実在するか
- 22. ★ Stripe Webhookの署名を検証しているか
- 23. ★ 同じ決済通知を二重に処理しないか
- 24. プロンプトインジェクションを受けても被害が広がらないか
- 25. 利用回数と課金額に上限があるか
- 26. MCPサーバーの出所と権限を把握しているか
公開の準備
- 27. 独自ドメインとHTTPSが正しくつながっているか
- 28. 送ったメールが迷惑メールに入らないか
- 29. タイトル、description、OGPを設定したか
- 30. 404とエラー画面から戻れるか
- 31. スマホで操作できるか
- 32. アクセス解析が動いているか
- 33. 表示の遅いページがないか
規約と個人情報
- 34. ★ 利用規約とプライバシーポリシーがあるか
- 35. ★ 有料サービスに必要な表示があるか
- 36. 取らなくてよい個人情報まで集めていないか
- 37. 退会とデータ削除ができるか
運用の準備
- 38. ログに個人情報や鍵を出していないか
- 39. バックアップから戻せるか一度試したか
- 40. 障害に気づける仕組みがあるか
- 41. 問い合わせ窓口が見つかるか
- 42. クラウドとAPIの利用料金に上限や通知があるか
全部にチェックが付かなくても大丈夫です。★の項目だけでも見ておけば、公開前の胸のザワザワはだいぶ収まるはずです。
わたしたちについて
最後に少しだけ自己です。
ここまでの項目を一つずつ手で確かめるのは、正直なかなか大変ですよね。
チェック項目があっても、目に見えにくい部分はブラックボックスになりやすいので「いつか何か問題が浮上するのでは」という不安がつきまといます。
BPR Prot. は、AIで作ったWebアプリを公開前に点検するためのサービスで、なかでも手間のかかるところをまとめて診断できるようにしています。
- サイトのURLを入れるだけで、セキュリティをA〜Fで採点
- コードに脆弱性がないか診断
- ファイルにマルウェアが紛れていないか検査
- 開発中に直接診断を呼び出すMCP連携 (Proプラン)
無料でも診断できるので、公開前の最終チェックにぜひお役立てください。

https://bpr-prot.com
Xで話しかけてもらえるとめちゃ嬉しいです!
フォローよろしくお願いします。 @BPR_Prot
最後まで見てくださりありがとうございました。
それでは良い開発ライフを!ノシ


