AIセキュリティ 2025年7月22日

AI生成コードの入力バリデーション不足問題

2025年3月、衝撃的な事件が発生しました。 vibe codingで作られた決済ゲートウェイが、入力バリデーション不備により **200万ドル(約3億円)** の不正決済を承認してしまいました。 入力バリデーションとは、ユーザーからの入力データが期待される形式・範囲であることを確認するプロセスです。

川西智也

合同会社ロイヤルピース 代表

アンチパターン⑩「入力バリデーション欠如」

$2M不正決済事件

2025年3月、衝撃的な事件が発生しました。

“In March 2025, a vibe-coded payment gateway approved $2M in fraudulent transactions due to inadequate input validation.”

vibe codingで作られた決済ゲートウェイが、入力バリデーション不備により 200万ドル(約3億円) の不正決済を承認してしまいました。


入力バリデーションとは:AI生成コードの脆弱性対策

入力バリデーションとは、ユーザーからの入力データが期待される形式・範囲であることを確認するプロセスです。

なぜ必要か:

  1. 不正な入力の防止: 想定外のデータを弾く
  2. セキュリティ: インジェクション攻撃の防止
  3. データ整合性: データベースの一貫性維持
  4. ユーザー体験: エラーメッセージによるガイド

【要注意】典型的な危険コードパターン

AIが生成しがちなバリデーション不足のコードを見てみましょう。

危険なコード:

// ❌ バリデーションなし
app.post('/payment', async (req, res) => {
  const { amount, cardNumber, cvv } = req.body;
  
  // 直接処理(何もチェックしていない)
  await processPayment(cardNumber, amount);
  
  res.json({ success: true });
});

攻撃の例:

// 負の金額で返金を騙し取る
{ "amount": -10000, "cardNumber": "1234567890123456" }

// 異常に大きな金額
{ "amount": 999999999, "cardNumber": "..." }

// SQLインジェクション
{ "amount": "100; DROP TABLE users;--" }

なぜAIはバリデーションを省略するのか

AIがバリデーションを省略する理由があります。

理由1: 「動く」ことが優先

  • 最短で動くコードを生成
  • バリデーションは「追加作業」

理由2: 明示的に依頼されていない

  • 「決済機能を作って」だけでは不十分
  • セキュリティ要件を指示しないと考慮しない

理由3: トレーニングデータの問題

  • チュートリアルはバリデーションを省略しがち
  • 実務レベルのセキュリティは含まれていない

実践的な解決策:厳密なバリデーション

正しいバリデーションの実装方法を解説します。

実践的な解決策1: zodを使ったスキーマバリデーション

import { z } from 'zod';

const paymentSchema = z.object({
  amount: z.number()
    .positive('金額は正の数である必要があります')
    .max(100000, '1回の決済上限は10万円です'),
  cardNumber: z.string()
    .regex(/^\d{16}$/, '16桁の数字で入力してください'),
  cvv: z.string()
    .regex(/^\d{3,4}$/, 'CVVは3〜4桁の数字です'),
  expiryMonth: z.number()
    .min(1).max(12),
  expiryYear: z.number()
    .min(2025).max(2035),
});

app.post('/payment', async (req, res) => {
  const result = paymentSchema.safeParse(req.body);
  
  if (!result.success) {
    return res.status(400).json({ 
      error: 'Validation failed',
      details: result.error.issues 
    });
  }
  
  await processPayment(result.data);
  res.json({ success: true });
});

実践的な解決策2: サニタイズ

import sanitizeHtml from 'sanitize-html';
import validator from 'validator';

// HTMLのサニタイズ
const cleanHtml = sanitizeHtml(userInput, {
  allowedTags: ['b', 'i', 'em', 'strong'],
  allowedAttributes: {}
});

// SQLインジェクション対策(プリペアドステートメント)
const query = 'SELECT * FROM users WHERE id = ?';
db.query(query, [userId]);

// XSS対策(エスケープ)
const escaped = validator.escape(userInput);

実践的な解決策3: 型チェック

interface PaymentRequest {
  amount: number;
  cardNumber: string;
  cvv: string;
  expiryMonth: number;
  expiryYear: number;
}

function validatePayment(data: unknown): PaymentRequest {
  if (typeof data !== 'object' || data === null) {
    throw new Error('Invalid request body');
  }
  
  const { amount, cardNumber, cvv, expiryMonth, expiryYear } = data as any;
  
  if (typeof amount !== 'number' || amount <= 0) {
    throw new Error('Invalid amount');
  }
  
  // ... 他のフィールドも検証
  
  return { amount, cardNumber, cvv, expiryMonth, expiryYear };
}

バリデーションの原則

効果的なバリデーションの原則があります。

原則1: ホワイトリスト方式

  • 許可する値を明示
  • 禁止する値を列挙するのではなく

原則2: サーバーサイドで必ず検証

  • クライアントサイドのバリデーションは補助
  • サーバーサイドが最終防衛線

原則3: 早期に失敗

  • 問題があれば即座にエラー
  • 処理を続行しない

原則4: エラーメッセージは慎重に

  • ユーザーには必要最小限
  • 攻撃者にヒントを与えない

プロンプトによるセキュリティ対策

AIに決済機能を依頼する際のプロンプト例です。

良いプロンプト:

決済機能を実装して:

## バリデーション要件
- zodスキーマでリクエストを検証
- 金額: 正の数、上限10万円
- カード番号: 16桁の数字
- CVV: 3〜4桁の数字
- 有効期限: 有効な日付

## 必須のセキュリティ要件
- サーバーサイドでバリデーション
- 不正な入力は400エラー
- エラーメッセージは最小限
- レート制限を実装

実装前チェックリスト

入力バリデーションのチェックリストです。

実装時:

  • すべての入力フィールドにバリデーションがあるか
  • 型チェックを行っているか
  • 範囲チェックを行っているか
  • 形式チェック(正規表現等)を行っているか

レビュー時:

  • サーバーサイドでバリデーションしているか
  • 負の値、ゼロ、異常に大きな値を弾いているか
  • SQLインジェクションを防いでいるか
  • エラーメッセージが詳細すぎないか

この事例から学ぶべき教訓と実践ポイント

「入力バリデーション欠如」から学ぶべきことは以下の通りです。

  1. $2Mの不正決済が発生

    • 入力バリデーション不備が原因
  2. AIはバリデーションを省略しがち

    • 明示的に依頼が必要
  3. zodなどのスキーマバリデーション

    • 型安全で堅牢
  4. サーバーサイドが最終防衛線

    • クライアントは信用しない
  5. ホワイトリスト方式

    • 許可する値を明示

まとめ:重要ポイントの振り返り

  • $2Mの不正決済 が入力バリデーション不備で発生
  • AIは バリデーションを省略 しがち
  • 解決策:zodスキーマ、サニタイズ、型チェック
  • サーバーサイド が最終防衛線
  • ホワイトリスト方式 で許可する値を明示
  • プロンプトで バリデーション要件を明示
  • 教訓:ユーザー入力は絶対に信用するな

実践的なスキルを習得しませんか?

ブログで学んだ知識を、研修で実践に変えましょう。