はじめに — 「個人開発だから大丈夫」という思い込み
「個人開発だし、ユーザーも少ないし、セキュリティは後回しでいいかな」
そう思っていた時期が、私にもありました。プロダクトを作ること自体が楽しくて、機能追加やUI改善に時間を使いたい気持ちはよく分かります。セキュリティ監査なんて、大企業のエンジニアがやることだと思っていたかもしれません。
しかし、個人開発こそセキュリティ監査が必要です。チームで開発していれば、コードレビューで誰かが「この API ルート、認証チェック入ってないよ」と指摘してくれます。個人開発にはその安全網がない。自分で見つけるしかないのです。
この記事では、2つのプロダクト(Wakulier と BandBridge)で実際にセキュリティ監査を行い、合計75件の問題を発見・修正した経験をもとに、個人開発者が実践できるセキュリティ監査チェックリストを紹介します。
2つの監査で75件の問題が見つかった
きっかけは、Wakulier(フリーランス向け依頼管理ツール)の開発がある程度落ち着いたタイミングでした。機能追加に追われる日々から少し余裕ができて、「そういえば、セキュリティのことちゃんと見たことがないな」と思ったのです。
2026年1月7日、Wakulier の初回セキュリティ監査を実施しました。Claude Code にコードベース全体のスキャンを依頼し、RLSポリシー、環境変数、認証フロー、未使用コードなどを一通りチェックした結果、22件の問題が見つかりました。
正直、ショックでした。自分ではそれなりに気をつけていたつもりだったからです。
その翌日、BandBridge(ミュージシャンマッチングサービス)でも同じ要領で監査を実施しました。こちらは開発初期段階で、コード量も多かったため、53件の問題が検出されました。
2026年1月8日の開発日記にはこう書いています。
セキュリティ監査は定期的に行うべき。開発中に気づかない問題が多い
開発中は「動くこと」に集中しているので、セキュリティ上のリスクに気づきにくい。これは個人開発に限らず、どんな開発体制でも同じかもしれません。ただ、個人開発の場合、レビューしてくれる人がいないぶん、意識的に立ち止まる機会を作る必要があります。
「チェックリスト化」が監査の質を上げる
Wakulier の監査を終えた時点で、1つ重要なことに気づきました。
2026年1月7日、Wakulier の開発日記にこう記録しています。
セキュリティ監査は「チェックリスト化」すると漏れにくい
最初の監査では、なんとなく「怪しそうなところを見て回る」という進め方をしていました。しかし、それだと観点の漏れが生じます。「RLS は見たけど、環境変数のチェックを忘れていた」ということが起きる。
BandBridge の監査では、Wakulier で得た知見をもとにチェックリストを作成してから臨みました。結果として、53件という多くの問題を体系的に洗い出すことができたのです。
以下が、2つの監査を通じて作り上げたチェックリストです。
チェックリスト 1:RLS ポリシー
Supabase を使っている場合、Row Level Security(RLS)はセキュリティの要です。RLS の設定ミスは、他のユーザーのデータが見えてしまうという致命的な問題につながります。
BandBridge の監査で記録した内容です。
RLSポリシーのテストは、複数ユーザーでの動作確認が必須
確認すべきポイント
- 全テーブルで RLS が有効になっているか: Supabase では、テーブル作成時にデフォルトで RLS が有効になりますが、マイグレーションで作成した場合は無効のままになっていることがあります
- SELECT / INSERT / UPDATE / DELETE それぞれにポリシーが設定されているか: SELECT ポリシーだけ設定して、UPDATE ポリシーを忘れているケースは意外と多い
- 他ユーザーのデータにアクセスできないか: 自分のアカウントでログインして動作確認するだけでは不十分。別のユーザーでログインし直して、他人のデータが見えないことを確認する
-- RLS が有効なテーブルを確認
SELECT tablename, rowsecurity
FROM pg_tables
WHERE schemaname = 'public';
-- 各テーブルのポリシーを確認
SELECT tablename, policyname, cmd
FROM pg_policies
WHERE schemaname = 'public';
RLS の設計パターンについては、Supabase RLS の設計パターン — デフォルト拒否で安全にで詳しく解説しています。
チェックリスト 2:環境変数
環境変数の管理は、個人開発で最も「なんとなく」で済ませがちな領域です。BandBridge の監査で、まさにその問題にぶつかりました。
環境変数の管理は
.env.localと Vercel の環境変数で二重管理になりがち
確認すべきポイント
.env.localと本番環境(Vercel等)の値が一致しているか: ローカルでは古い値を使い続けていて、本番だけ新しい値に更新している、あるいはその逆のケースがあります- 不要な環境変数が残っていないか: 以前使っていたサービスの API キーがそのまま
.env.localに残っていると、万が一流出したときのリスクになります NEXT_PUBLIC_プレフィックスの使い分けが正しいか:NEXT_PUBLIC_をつけた環境変数はクライアントに公開されます。シークレットキーに誤ってこのプレフィックスをつけていないか確認してください.env.localが.gitignoreに含まれているか: 基本中の基本ですが、念のため確認。新しいプロジェクトをセットアップしたときに.gitignoreの設定を忘れることがあります
# .gitignore に .env* が含まれているか確認
grep -n "\.env" .gitignore
# NEXT_PUBLIC_ 付きの環境変数を一覧
grep "NEXT_PUBLIC_" .env.local
環境変数の棚卸しは、監査のたびに行うことをお勧めします。「このキーは何のために使っているんだっけ」と思うものがあれば、それは削除候補です。
チェックリスト 3:認証フロー
認証は「動いているから大丈夫」と思いがちですが、細かいところに穴が潜んでいることがあります。
確認すべきポイント
- 未認証ユーザーが保護ページにアクセスできないか: URLを直接入力してアクセスしたとき、ちゃんとリダイレクトされるか
- セッション切れ時の挙動: ログインしたまま長時間放置して、操作を再開したとき、エラーにならず適切にリダイレクトされるか
- middleware.ts の保護対象パスが正しいか: 新しいページを追加したとき、middleware のパスパターンに含め忘れていないか
- OAuth コールバック URL が正しいか: 本番環境とローカル環境で異なる URL を設定している場合、切り替えミスがないか
Supabase Auth と Next.js の組み合わせでは、middleware.ts がセッション管理の要になります。認証周りで問題が起きやすいポイントについては、Supabase Auth + Next.js App Router で認証が切れる問題と解決策も参考にしてください。
チェックリスト 4:未使用コード・エンドポイント
Wakulier の監査で、もう使っていない API エンドポイントが残っていることに気づきました。
未使用コードは積極的に削除(技術的負債を減らす)
Wakulier では、開発初期に作成した /api/settings というエンドポイントが不要になっていたため、監査のタイミングで削除しました。
なぜ未使用コードが危険なのか
未使用のAPIエンドポイントは「攻撃対象領域(Attack Surface)」を広げます。使っていないコードにはテストが書かれていないことが多く、脆弱性があっても気づきにくい。誰も見ていない裏口が開いたままになっているようなものです。
確認すべきポイント
- 使っていない API ルートがないか:
src/app/api/配下のファイルを一つずつ確認し、フロントエンドから呼ばれていないルートを特定する - 使っていないページ(ルート)がないか: 開発中に作ったテスト用ページが残っていないか
- 使っていない npm パッケージがないか:
package.jsonの dependencies を確認。不要なパッケージは脆弱性の潜在的な入り口になる - デバッグ用コードが残っていないか:
console.logでユーザー情報を出力していないか、開発用のバイパスコードが残っていないか
# API ルートの一覧を取得
ls src/app/api/
# console.log を検索(機密情報の出力チェック)
grep -rn "console.log" src/app/api/ src/lib/
「もったいない」という気持ちは分かりますが、使っていないコードは削除する方がセキュリティ上は安全です。必要になったら Git の履歴から復元できます。
チェックリスト 5:エラーメッセージの情報漏洩
エラーメッセージは、攻撃者にとって貴重な情報源になり得ます。個人開発では、開発中の便利さを優先して詳細なエラーメッセージを返しがちです。
確認すべきポイント
- API レスポンスにスタックトレースが含まれていないか: 開発環境では便利ですが、本番環境では内部構造が露出するリスクがあります
- データベースのエラーメッセージをそのまま返していないか: テーブル名やカラム名が含まれるエラーは、攻撃者にデータベース構造のヒントを与えます
- 認証エラーで「ユーザーが存在しない」と「パスワードが違う」を区別していないか: 区別すると、攻撃者にユーザーの存在有無が分かってしまいます
// ❌ NG: 詳細なエラーを返してしまう
catch (error) {
return Response.json({ error: error.message }, { status: 500 });
}
// ✅ OK: ユーザー向けには汎用メッセージ、ログには詳細を残す
catch (error) {
console.error('Internal error:', error);
return Response.json(
{ error: '処理中にエラーが発生しました' },
{ status: 500 }
);
}
本番環境では「何が起きたか」をユーザーに伝える必要はありません。ユーザーには汎用的なメッセージを返し、詳細はサーバーのログに記録する。これが基本です。
優先度の付け方 — Critical / High / Medium
BandBridge の監査では53件の問題が見つかりましたが、すべてを同時に修正するのは現実的ではありません。PMとして、優先度を付けて段階的に対応する判断をしました。
Critical(即座に対応)
- RLS ポリシーの欠落(他ユーザーのデータが見える)
- シークレットキーのクライアント露出
- 認証バイパスが可能な状態
High(1週間以内に対応)
- 不要な API エンドポイントの削除
- 環境変数の不整合
- エラーメッセージの情報漏洩
Medium(次回リリースまでに対応)
- 未使用パッケージの削除
console.logの除去- コードコメントの機密情報
Wakulier では Claude Code を使って22件すべてをその日のうちに修正できましたが、BandBridge は数日に分けて対応しました。重要なのは、Critical の問題を見つけたらすぐに修正すること。High 以下は計画的に対応すればよいのです。
監査を「習慣」にする
2回の監査を通じて学んだ最も大きな教訓は、セキュリティ監査は一度やって終わりではないということです。
コードは日々変化します。新しい機能を追加するたびに、新しいAPIルートが増え、新しいRLSポリシーが必要になり、新しい環境変数が追加される。監査を定期的に行わなければ、知らないうちに穴が広がっていきます。
監査を習慣化するためのヒント
1. タイミングを決める
「月に1回、月初にセキュリティ監査を行う」のように、スケジュールに組み込んでしまうのが確実です。「気が向いたらやる」では、いつまでもやらないまま終わります。
2. 結果を記録する
監査で見つかった問題とその対応を記録しておくと、次回の監査の参考になります。Wakulier と BandBridge の両方で監査レポートを作成しましたが、BandBridge の監査では Wakulier のレポートを参照してチェック観点を改善できました。
3. チェックリストを更新する
新しい問題パターンを発見したら、チェックリストに追加します。チェックリストは「過去の失敗の集積」です。監査を重ねるほど、チェックリストは精度の高いものになっていきます。
4. ボット対策も忘れずに
セキュリティ監査はコードの内側に注目しがちですが、外部からの攻撃への備えも重要です。認証なしフォームへのボット対策については、Cloudflare Turnstile で認証なしフォームをボットから守るで解説しています。
まとめ — 個人開発でもセキュリティは「仕組み」で守る
2つのプロダクトで計75件の問題を発見した経験から、個人開発でもセキュリティ監査が不可欠だと実感しました。
改めて、チェックリストの全体像をまとめます。
| カテゴリ | 主な確認項目 |
|---|---|
| RLS ポリシー | 全テーブルの有効化、操作別ポリシー、複数ユーザーテスト |
| 環境変数 | ローカルと本番の一致、不要キーの削除、NEXT_PUBLIC_ の使い分け |
| 認証フロー | 保護ページのアクセス制御、セッション切れ、middleware パス |
| 未使用コード | 不要 API ルート、テストページ、npm パッケージ、デバッグコード |
| エラーメッセージ | スタックトレースの非公開、DB エラーの隠蔽、認証エラーの汎用化 |
大切なのは、セキュリティ監査を「特別なイベント」ではなく「定期的な習慣」にすることです。チェックリストがあれば30分から1時間で一通り確認できます。月に1回、この時間を投資するだけで、プロダクトの安全性は大きく向上します。
「個人開発だからセキュリティは後回し」ではなく、「個人開発だからこそ仕組みで守る」。この発想の転換が、ユーザーの信頼を得る第一歩になるのではないかと思います。
Zeronova(ゼロノバ)
Product Manager / AI-Native Builder
Web/IT業界19年以上・20以上のWebサービスを担当したPdM。東証プライム上場企業の子会社代表として事業経営を経験。現在はAIを駆使して企画から実装まで完結させる個人開発を実践中。