7
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

AIでアプリを量産する時代の「出す前5分」セキュリティ最低限ガイド|コピペ・チェックリスト付き(2026)

7
Last updated at Posted at 2026-06-18

個人開発でWebアプリをどんどん出す人向け。出す前の5分で通せる最低限の衛生と、機能を足したときだけ発火させる追加対策を、コピペできる形でまとめた。

なぜ「自分の小さなアプリ」にも要るのか

「お金もユーザーもいないアプリは狙われない」とよく聞く。これは誤解だ。

現代の攻撃の主流は、人が選ぶ標的型ではなく、botによる無差別・自動スキャンである。攻撃者はネット全体を機械的に走査し、既知の穴を見つけ次第に侵入する。狙われる理由は「お金」ではなく「届く・自動化できる」からだ。

小さなアプリでも、乗っ取られれば 踏み台・スパム中継・マイニング・フィッシング配信 に使われる。ユーザーのメールやパスワード(使い回しに価値がある)も盗まれる。「お金がない=安全」は成り立たない。狙われているのは銀行残高ではなく、サーバーとユーザーのデータだ。

AIでアプリを量産できる時代ほど、これは効いてくる。生成は速いが、生成物の安全は誰も保証してくれない。出す数が増えるほど、出す前の最低限が雑になりやすい。

考え方:リスク = 資産 × 確率 × 影響

全部を完璧にやる必要はない。守るべき重さは「持っている資産 × 攻撃される確率 × 壊れたときの影響」で決まる。

  • 高価な対策(ペンテスト / WAF / 監視)は、守る物(ユーザー・データ)ができてから。
  • 安いベースライン衛生は、初日から。自動・無差別攻撃は“定数”として常にかかるからだ。

この記事の A が初日からの定数、B が機能追加で発火するトリガーである。

A. 出す前5分の「非交渉」チェック

新規アプリごとに、上から通すだけでいい。

  • 秘密情報をコード/リポに置かない.env を gitignore・鍵の直書きゼロ)
  • HTTPSのみ(多くのPaaSは自動。HTTP→HTTPSリダイレクトを確認)
  • セキュリティヘッダ一括(Express: helmet()
  • リクエストサイズ制限(巨大ボディ拒否)
  • 基本レート制限
  • 依存を最新&監査npm audit + Dependabot)
  • エラーで内部情報を漏らさない(stack traceをユーザーに返さない)
  • CORSは具体オリジンだけ* を使わない・特にcredentials時)
  • ログに秘密/PIIを出さない
  • 本番にデバッグ/管理画面を晒さない

B. 機能を足したら“発火”するトリガー

足す機能 発火する対策
認証/ログイン パスワードは bcrypt/argon2 でハッシュ・自作認証しない・cookieは HttpOnly + Secure + SameSite
DB パラメータ化クエリ(文字列連結SQL禁止=SQLi防止)・DBユーザは最小権限
ユーザー入力の表示 出力エスケープ(XSS防止)・入力バリデーション
個人データ取得 ↓「個人情報トリガー」(法的義務が立つ)
決済 自前でカード情報を持たない(Stripe等に委譲)・PCI範囲を外に出す
Webhook/外部連携 署名検証必須(送信元が本物か確認)
ファイルアップロード 種別/サイズ制限・実行可能領域に置かない

個人データを取った瞬間(個人情報保護法)

  • 取得は最小限・利用目的を明示・プライバシーポリシー設置
  • 安全管理措置(アクセス制御・暗号化・アクセスログ)
  • 漏洩時の報告ルート(個人情報保護委員会への報告+本人通知が、一定の場合は義務)

C. コピペ資産(Node/Express)

.gitignore

.env
.env.*
node_modules/
*.pem
*.key

セキュリティヘッダ+サイズ制限+レート制限

import helmet from 'helmet';
import rateLimit from 'express-rate-limit';

app.use(helmet());                          // CSP/HSTS/X-Content-Type-Options 等を一括
app.use(express.json({ limit: '100kb' }));  // 巨大ボディ拒否
app.use(rateLimit({ windowMs: 60_000, max: 60 })); // 1分60回まで

セッションcookie

res.cookie('session', token, { httpOnly: true, secure: true, sameSite: 'lax' });

パスワードのハッシュ

import bcrypt from 'bcrypt';
const hash = await bcrypt.hash(password, 12);
const ok   = await bcrypt.compare(input, hash);

パラメータ化クエリ(SQLi防止)

// ❌ `SELECT * FROM users WHERE id = '${id}'`
// ✅
db.query('SELECT * FROM users WHERE id = $1', [id]);

エラーで内部を漏らさない

app.use((err, req, res, _next) => {
  console.error(err);                                        // ログには残す
  res.status(500).json({ error: 'Internal Server Error' });  // ユーザーには詳細を出さない
});

Webhook 署名検証(生ボディで計算・タイミング安全に比較)

import crypto from 'crypto';
function verifySignature(rawBody, signature, secret) {
  const expected = crypto.createHmac('sha256', secret).update(rawBody).digest('base64');
  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
}
// 署名ヘッダと比較。raw body を使う(JSON.parse 後ではダメ)。

Dependabot(.github/dependabot.yml)

version: 2
updates:
  - package-ecosystem: "npm"
    directory: "/"
    schedule:
      interval: "weekly"

まとめ

高価な対策 → 守る物(ユーザー/データ)に合わせて後で
ベースライン衛生 → 初日から(安い・自動攻撃に常時さらされる)
個人データ → 持った瞬間に法的義務とリスク移転(保険/委譲)を真剣に

量産しても、各アプリが裸で出ていかないように。A を5分で通し、機能を足すたびに B を発火させる。これだけで、致命的な事故のほとんどは初日に防げる。


思想・構成・校閲:cmalu ractu
文章生成:Claude(Anthropic)

7
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?