📋 スキーマユーティリティ
Nodeblocks SDK は、リクエスト検証のためのセキュリティ拡張付き AJV スキーマヘルパーを提供します。これらのユーティリティは、予期しないフィールドとクエリフィルター内の NoSQL インジェクションを防ぎます。
🎯 概要
import { utils } from '@nodeblocks/backend-sdk';
const {
createAjvInstance,
addMongoFilterKeyword,
applySchemaDefaults,
applyDefaultSchemaEnhancements,
} = utils;
このモジュールは 4 つの関数をエクスポートします。AJV スキーマ検証とは異なるルートレベルのビジネスロジックバリデーターは、Validator に記載されています。
primitives の withSchema コンポーザーはこれらのヘルパーを内部で使用します。Route Component を参照してください。
🏭 AJV インスタンス
createAjvInstance
事前構成済みの AJV インスタンスを作成します。
import { utils } from '@nodeblocks/backend-sdk';
const { createAjvInstance } = utils;
const ajv = createAjvInstance();
const validate = ajv.compile(schema);
適用される構成:
allErrors: true— すべての検証エラーを収集coerceTypes: true— クエリ/本文の型を強制変換useDefaults: true— スキーマデフォルトを適用ajv-formats— 形式検証(email、date-time など)addMongoFilterKeyword—queryFilterカスタムキーワードを登録
🛡️ NoSQL インジェクション保護
addMongoFilterKeyword
既存の AJV インスタンスに queryFilter カスタム AJV キーワードを登録します。オブジェクトスキーマで queryFilter: true を設定すると、検証済みデータは MongoDB クエリフィルターの安全規則に対して検査されます。
import Ajv from 'ajv';
import { utils } from '@nodeblocks/backend-sdk';
const { addMongoFilterKeyword } = utils;
const ajv = new Ajv();
addMongoFilterKeyword(ajv);
createAjvInstance() はこれを自動的に呼び出します。
検証レイヤー:
| レイヤー | 保護 |
|---|---|
| 型安全性 | カスタムキーワードはオブジェクトスキーマで実行されます。非オブジェクト値は基になる安全性検査で受け入れられます。 |
| プロトタイプ汚染 | フィルターを再帰的に走査しながら、列挙可能な __proto__、constructor、prototype キーを拒否します。 |
| 演算子ホワイトリスト | $eq、$ne、$gt、$gte、$lt、$lte、$in、$nin、$regex、$options、$and、$or のみを許可します。 |
| 正規表現の安全性 | $regex は 100 文字以下の文字列であり、safe-regex(ReDoS 保護)を通過する必要があります。 |
| 再帰検証 | ネストしたオブジェクトと配列をすべての深さで検証します。 |
ブロックされる演算子には、$where、$expr、$function などの危険なものが含まれます。
エラーメッセージは、データベース詳細の漏洩を避けるため意図的に汎用的です("Invalid query filter format")。
スキーマ例:
const schema = {
type: 'object',
queryFilter: true,
properties: {
email: { type: ['string', 'object'] },
age: { type: ['number', 'object'] },
},
};
const validate = createAjvInstance().compile(schema);
validate({ email: { $in: ['user@example.com'] } }); // 有効
validate({ email: 'user@example.com', $where: 'sleep(10000)' }); // 無効
🔧 スキーマ拡張
applySchemaDefaults
JSON Schema にデフォルトのプロパティ値を再帰的に適用します。
import { utils } from '@nodeblocks/backend-sdk';
const { applySchemaDefaults } = utils;
const enhanced = applySchemaDefaults(
mySchema,
{ additionalProperties: false },
(schema) => schema.type === 'object'
);
パラメーター:
schema: 拡張するJSONSchema7defaults: プロパティ名からデフォルト値へのマップcondition: 省略可能な述語。デフォルトでは、type === 'object'、typeに'object'が含まれる、またはスキーマにproperties/patternPropertiesがある場合に適用
デフォルトは properties、allOf、oneOf、anyOf、配列の items に再帰的に適用されます。スキーマ上の既存値は上書きされません。
applyDefaultSchemaEnhancements
SDK のセキュリティデフォルトをオブジェクトスキーマに再帰的に適用します。
import { utils } from '@nodeblocks/backend-sdk';
const { applyDefaultSchemaEnhancements } = utils;
const secureSchema = applyDefaultSchemaEnhancements(routeSchema);
適用されるデフォルト(オブジェクト型のみ、再帰的):
additionalProperties: false— 未定義フィールドをブロックqueryFilter: true— MongoDB クエリフィルター検証を有効化
単純なプロパティ型(string、number など)は変更されません。
📐 ベストプラクティス
1. ルートスキーマには applyDefaultSchemaEnhancements を使用する
// ✅ 良い例: すべてのオブジェクトスキーマにセキュリティデフォルトを適用
const schema = applyDefaultSchemaEnhancements(myRouteSchema);
2. スキーマ検証とビジネスバリデーターを区別する
AJV スキーマユーティリティは構造と安全性を検証します。ビジネス規則(所有権、ロール、一意性)は Validator 関数に属します。
3. フィルターオブジェクトでは queryFilter を有効に保つ
別のインジェクション防御がない限り、ユーザーが制御するクエリオブジェクトで queryFilter を無効にしないでください。
🔗 関連項目
- Validator — ルートレベルのビジネスロジックバリデーター
- Route Component —
withSchemaコンポーザー統合 - Authentication ユーティリティ — トークンとリクエストのセキュリティ(スキーマ検証とは別)