mcpField
D
defense-in-depth-validation

defense-in-depth-validation

github.com/secondsky開発240423 回インストール5 週間前に更新
リポジトリ

defense-in-depth-validation について

Defense-in-Depth Validationは、無効なデータによるバグを減らすための開発者向け実践ガイドです。入口、ビジネスロジック、環境ガード、デバッグ記録の各層に検証を配置します。

主な機能

  1. 01入口での入力検証
  2. 02ビジネスロジックの検証
  3. 03環境依存操作のガード
  4. 04デバッグ情報の記録

活用シーン

  1. 01無効なパスによる意図しないGit操作の防止
  2. 02複数のデータ経路における検証漏れの確認
  3. 03マルチテナント要求への段階的な認可チェックの追加

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/secondsky/claude-skills --skill defense-in-depth-validation

インストール後、Claude Code で/defense-in-depth-validationを入力して読み込まれたか確認します。

詳細

多層防御による検証

概要

無効なデータが原因のバグを修正するとき、1か所で検証を追加すれば十分だと感じることがあります。しかし、その単一のチェックは、異なるコードパスやリファクタリング、モックによって回避される可能性があります。

基本原則: データが通過するすべての層で検証します。バグが構造上起こり得ないようにします。

複数の層が必要な理由

単一の検証:「バグを修正しました」 複数の層:「バグが起こり得ないようにしました」

層ごとに異なるケースを検出します。

  • エントリーポイントでの検証は、ほとんどのバグを検出します
  • ビジネスロジックでの検証は、エッジケースを検出します
  • 環境ガードは、特定のコンテキストでの危険を防ぎます
  • デバッグログは、ほかの層で検出できなかった場合に役立ちます

4つの層

レイヤー 1:エントリーポイントでの検証

目的: API の境界で明らかに無効な入力を拒否します

function createProject(name: string, workingDirectory: string) {
  if (!workingDirectory || workingDirectory.trim() === '') {
    throw new Error('workingDirectory cannot be empty');
  }
  if (!existsSync(workingDirectory)) {
    throw new Error(`workingDirectory does not exist: ${workingDirectory}`);
  }
  if (!statSync(workingDirectory).isDirectory()) {
    throw new Error(`workingDirectory is not a directory: ${workingDirectory}`);
  }
  // ... proceed
}
レイヤー 2:ビジネスロジックでの検証

目的: データがこの操作に適していることを確認します

function initializeWorkspace(projectDir: string, sessionId: string) {
  if (!projectDir) {
    throw new Error('projectDir required for workspace initialization');
  }
  // ... proceed
}
レイヤー 3:環境ガード

目的: 特定のコンテキストで危険な操作が行われないようにします

async function gitInit(directory: string) {
  // In tests, refuse git init outside temp directories
  if (process.env.NODE_ENV === 'test') {
    const normalized = normalize(resolve(directory));
    const tmpDir = normalize(resolve(tmpdir()));

    if (!normalized.startsWith(tmpDir)) {
      throw new Error(
        `Refusing git init outside temp dir during tests: ${directory}`
      );
    }
  }
  // ... proceed
}
レイヤー 4:デバッグ用の計測

目的: 調査に必要なコンテキストを記録します

async function gitInit(directory: string) {
  const stack = new Error().stack;
  logger.debug('About to git init', {
    directory,
    cwd: process.cwd(),
    stack,
  });
  // ... proceed
}

パターンの適用

バグを見つけたときは、次の手順に従います。

  1. データフローをたどる - 不正な値はどこで発生し、どこで使われていますか?
  2. すべてのチェックポイントを洗い出す - データが通過するすべてのポイントを列挙します
  3. 各層に検証を追加する - エントリーポイント、ビジネスロジック、環境、デバッグ
  4. 各層をテストする - レイヤー 1 を回避し、レイヤー 2 が検出することを確認します

セッションでの例

バグ:空の projectDir によって、ソースコード内で git init が実行されました

データフロー:

  1. テストのセットアップ → 空文字列
  2. Project.create(name, '')
  3. WorkspaceManager.createWorkspace('')
  4. process.cwd() 内で git init が実行される

追加した4つの層:

  • レイヤー 1:Project.create() で空でないこと、存在すること、書き込み可能であることを検証
  • レイヤー 2:WorkspaceManager で projectDir が空でないことを検証
  • レイヤー 3:テスト中、WorktreeManager が tmpdir の外での git init を拒否
  • レイヤー 4:git init の前にスタックトレースを記録

結果: 1847 件のテストがすべて成功し、バグを再現できなくなりました

重要なポイント

4つの層すべてが必要でした。テスト中、各層はほかの層が見逃したバグを検出しました。

  • 異なるコードパスがエントリーポイントでの検証を回避しました
  • モックがビジネスロジックのチェックを回避しました
  • 異なるプラットフォームでのエッジケースには環境ガードが必要でした
  • デバッグログによって構造上の誤用が特定されました

検証ポイントを1つ設けただけで終わりにしないでください。 すべての層にチェックを追加します。

セキュリティの多層防御

同じ多層アプローチは、セキュリティ制御の標準的なパターンです。信頼は単一のポイントで与えないため、どの層でバグや回避が発生しても、それだけでシステムが侵害されることはありません。各リクエストは、エッジ、ハンドラー、データ層でそれぞれ独立してチェックされます。

  • レイヤー 1(エッジ):エッジ(Cloudflare や AWS WAF などの CDN/WAF)でレート制限とフィルタリングを行い、不正なトラフィックがオリジンに到達しないようにします。
  • レイヤー 2(ハンドラー):セッションに基づいてサーバー側で認可を再導出します — 本文の userId のように、クライアントが指定した申告を決して信頼しないでください。
  • レイヤー 3(データ):データベースクエリで所有権の不変条件を強制し、ハンドラーにバグがあってもテナントの境界を越えられないようにします。
// Layer 2 — re-derive authz server-side, never trust client claims
app.put('/docs/:id', async (req, res) => {
  const user = await verifySession(req.cookies.session); // throws if invalid
  // Layer 3 — DB clause re-checks ownership; a handler bug still can't cross tenants
  const updated = await db.query(
    'UPDATE docs SET title = $1 WHERE id = $2 AND owner_id = $3 RETURNING *',
    [req.body.title, req.params.id, user.id]
  );
  if (!updated.rowCount) return res.status(403).send('Not allowed');
  res.json(updated.rows[0]);
});

多層防御とは、どの単一の層で障害が発生しても、それだけでシステムが侵害されることはないということです。

コメント