「よし、ついにアプリが完成した!早速リリースしよう!」…ちょっと待ってください。そのアプリ、セキュリティは大丈夫ですか?
バイブコーディングは確かに楽しいし、アイデアを素早く形にできる素晴らしい開発手法です。しかし、セキュリティが抜け落ちやすいのも事実。リリース後に「APIキーが丸見えで高額請求が来た」「データベースを全削除された」「個人情報が流出した」といったトラブルが発覚すると、信用失墜と金銭的損失は避けられません。
この記事では、非エンジニアでもわかる「リリース前の最低限チェックリスト」をお届けします。たった数時間の確認作業で、大きなトラブルを防げるはずです。
なぜバイブコーダーがセキュリティで失敗するのか
バイブコーディングでは「とりあえず動かす」ことを優先するため、以下のような状況になりがちです:
- ローカル環境では問題なく動作するが、本番環境では危険な状態
- チュートリアル通りの設定をそのまま使用(セキュリティ設定が緩い)
- 動作確認に集中してセキュリティテストを後回し
- エラーが出ないから安全と思い込む
実際の被害例を見てみましょう:
- ChatGPT APIキー漏洩:1日で3万円の不正利用被害
- MongoDB認証なし:ユーザーデータ全削除+身代金要求
- AWS認証情報露出:マイニング攻撃で月20万円請求
これらはすべて、リリース前の5分間チェックで防げた事故です。
【チェック1】APIキーがユーザーから見えていないか
危険な状態とは
以下のような状態になっていると、APIキーが丸見えです:
// ❌ 絶対にダメな例
const openaiApiKey = "sk-abc123..."; // ソースコードに直接記述
const response = await fetch("https://api.openai.com/v1/chat/completions", {
headers: {
"Authorization": `Bearer sk-abc123...` // ハードコーディング
}
});
この状態でリリースすると、誰でもあなたのAPIキーを使って課金サービスを利用できる状態になります。
被害の具体例
- ChatGPT API:GPT-4を大量実行されて1日3万円請求
- Google Maps API:位置情報検索を無限実行されて月5万円
- SendGrid API:スパムメール送信に悪用されてアカウント停止
簡単な確認方法
Step 1: ブラウザの開発者ツールで確認
- 公開されたアプリをブラウザで開く
- F12キーを押して開発者ツールを開く
- 「Network」タブをクリック
- アプリを操作してAPIが呼ばれる機能を実行
- 通信一覧で外部API(openai.com、googleapis.com等)への通信をクリック
- 「Headers」セクションで Authorization や API-Key を確認
Step 2: ソースコード確認
- ブラウザで右クリック→「ページのソースを表示」
- Ctrl+Fで以下を検索: – “sk-” (OpenAI) – “AIza” (Google API) – “Bearer ” – “API_KEY”
正しい対策
環境変数+サーバーサイドでの処理が基本です:
// ✅ 正しい例(Next.js)
// pages/api/chat.js - サーバーサイドでAPI呼び出し
export default async function handler(req, res) {
const apiKey = process.env.OPENAI_API_KEY; // 環境変数から取得
const response = await fetch("https://api.openai.com/v1/chat/completions", {
headers: {
"Authorization": `Bearer ${apiKey}`
},
body: JSON.stringify(req.body)
});
const data = await response.json();
res.json(data);
}
# .env.local ファイル(ローカル用)
OPENAI_API_KEY=sk-your-actual-key-here
# 本番環境では Vercel/Netlify の環境変数設定画面で設定
【チェック2】APIが勝手に叩ける状態じゃないか
危険な状態とは
以下のようなAPIエンドポイントがあると、誰でもデータを取得・操作できる状態です:
// ❌ 危険な例:認証なしでユーザー情報を全件取得
// /api/users/all.js
export default async function handler(req, res) {
const users = await db.collection('users').find({}).toArray();
res.json(users); // 全ユーザーの情報が丸見え
}
よくある危険パターン
- ユーザー一覧API:/api/users で全ユーザー情報取得可能
- 管理者用API:/api/admin/delete で認証なしで削除可能
- データ投稿API:認証なしで掲示板やコメントに投稿可能
- ファイルアップロードAPI:無制限にファイルアップロード可能
確認方法
Step 1: API エンドポイント一覧の確認
プロジェクトフォルダで以下をチェック:
- pages/api/ フォルダ内のファイル一覧
- app/api/ フォルダ内のファイル一覧(Next.js 13+)
- 各ファイルで認証チェックの有無を確認
Step 2: 実際にアクセステスト
- ブラウザのアドレスバーに直接APIのURLを入力
- 例:https://yourapp.com/api/users
- ログインしていない状態でアクセス
- データが表示されたら危険
正しい対策
// ✅ 正しい例:認証チェック付きAPI
import { verifyToken } from '../../../lib/auth';
export default async function handler(req, res) {
try {
// 認証チェック
const token = req.headers.authorization?.replace('Bearer ', '');
const user = await verifyToken(token);
if (!user) {
return res.status(401).json({ error: '認証が必要です' });
}
// 認可チェック(必要に応じて)
if (user.role !== 'admin') {
return res.status(403).json({ error: '管理者権限が必要です' });
}
// 実際の処理
const users = await db.collection('users').find({}).toArray();
res.json(users);
} catch (error) {
res.status(500).json({ error: 'サーバーエラー' });
}
}
【チェック3】データベースが全削除される危険性はないか
Supabase RLS(Row Level Security)の確認
Supabaseを使っている場合、RLSが無効だと誰でもデータベースを操作できます。
危険な設定例:
-- ❌ RLSが無効な状態
-- テーブル作成時にRLSを有効にしていない
CREATE TABLE users (
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
email TEXT,
password TEXT
);
-- この状態だと誰でも全ユーザーのデータにアクセス可能
確認方法
Supabaseダッシュボードでの確認手順:
- Supabaseプロジェクトのダッシュボードにアクセス
- 左メニューから「Authentication」→「Policies」を選択
- 各テーブルで「RLS enabled」になっているか確認
- 適切なポリシーが設定されているか確認
実際のテスト方法:
// ブラウザのコンソールで実行してテスト
const { createClient } = supabase;
const supabaseUrl = 'YOUR_SUPABASE_URL';
const supabaseKey = 'YOUR_ANON_KEY'; // 公開されているキー
const client = createClient(supabaseUrl, supabaseKey);
// 認証なしでデータ取得を試す
const { data, error } = await client
.from('users')
.select('*');
console.log(data); // データが取得できたら危険
正しい設定
-- ✅ 正しい設定:RLS有効+適切なポリシー
-- RLSを有効化
ALTER TABLE users ENABLE ROW LEVEL SECURITY;
-- ユーザーは自分のデータのみ閲覧可能
CREATE POLICY "ユーザーは自分のデータのみ閲覧可能" ON users
FOR SELECT USING (auth.uid() = id);
-- ユーザーは自分のデータのみ更新可能
CREATE POLICY "ユーザーは自分のデータのみ更新可能" ON users
FOR UPDATE USING (auth.uid() = id);
その他の見落としがちなセキュリティ穴
GitHubでの環境変数漏洩
確認方法:
- GitHubリポジトリで「.env」ファイルが含まれていないか確認
- .gitignoreに以下が含まれているか確認:
# 必須項目
.env
.env.local
.env.production
.env.staging
*.log
node_modules/
推測可能な管理画面URL
危険な例:
- /admin
- /dashboard
- /管理
- /control
対策:
- 推測しにくいURL(例:/admin-xk9p2m)を使用
- IP制限を設定
- 二要素認証を必須にする
CORSの過度な設定
// ❌ 危険な設定
app.use(cors({
origin: "*", // すべてのドメインからアクセス可能
credentials: true
}));
// ✅ 正しい設定
app.use(cors({
origin: ["https://yourdomain.com", "https://www.yourdomain.com"],
credentials: true
}));
パスワードの平文保存
確認方法:データベースでユーザーテーブルのpasswordカラムを直接確認
// ❌ 危険:平文保存
const user = {
email: "user@example.com",
password: "password123" // そのまま保存
};
// ✅ 正しい:ハッシュ化
import bcrypt from 'bcryptjs';
const hashedPassword = await bcrypt.hash(password, 12);
const user = {
email: "user@example.com",
password: hashedPassword // ハッシュ化して保存
};
リリース前5分でできる最終確認手順
以下のチェックリストを必ず実行してからリリースしましょう:
1分目:APIキー漏洩チェック
- ブラウザでF12→Networkタブ→API呼び出し確認
- ソースコード表示でAPIキー検索(”sk-“, “AIza”, “Bearer”)
- GitHubで.envファイルがコミットされていないか確認
2分目:API認証チェック
- ログアウト状態で /api/users などのAPIに直接アクセス
- エラーが出るか、データが表示されるかを確認
- 管理者用APIへの認証なしアクセスを試行
3分目:データベースセキュリティ
- Supabase: RLS有効化確認
- MongoDB: 認証設定確認
- MySQL/PostgreSQL: ユーザー権限確認
4分目:設定ファイル確認
- CORS設定が適切か(origin: “*” になっていないか)
- 管理画面URLが推測困難か
- 本番環境の環境変数が正しく設定されているか
5分目:総合確認
- 第三者の立場でアプリを触ってみる
- 意図しない機能にアクセスできないか確認
- エラーメッセージで内部情報が漏洩していないか確認
まとめ:このチェックリストで事故を防ごう
セキュリティは「リリース前の数時間」で大きく改善できます。完璧でなくても、基本的なチェックを行うだけで99%の事故は防げます。
重要なのは以下の3点です:
- APIキーを絶対にフロントエンドに露出させない
- すべてのAPIエンドポイントに適切な認証を設ける
- データベースのアクセス制御を正しく設定する
非エンジニアの方も、ブラウザの開発者ツール+このチェックリストがあれば事前確認は十分可能です。
この記事をブックマークして、次回リリース時に必ず確認してください。あなたの大切なアプリと、ユーザーの信頼を守るために。
もしこの記事が役に立ったら、同じようにバイブコーディングを楽しんでいる仲間にもシェアしてもらえると嬉しいです。みんなで安全な開発環境を作っていきましょう!
