При проектировании схем валидации на основе Ajv важен не только этап проверки структуры данных, но и их приведение к безопасному и предсказуемому виду. Санитизация в данном контексте означает преобразование входных данных к нормализованной форме: удаление лишних полей, приведение типов, установка значений по умолчанию, очистка строк и устранение потенциально опасных конструкций.
Одной из базовых возможностей Ajv является автоматическое приведение типов, которое активируется через опцию конфигурации:
const ajv = new Ajv({
coerceTypes: true
});
При включённой опции строковые значения могут преобразовываться в числа, булевы значения или другие типы в соответствии со схемой:
const schema = {
type: "object",
properties: {
age: { type: "integer" },
active: { type: "boolean" }
},
required: ["age", "active"]
};
const validate = ajv.compile(schema);
const data = {
age: "25",
active: "true"
};
validate(data);
// результат после коэрции:
// data = { age: 25, active: true }
Такой механизм снижает необходимость ручной нормализации и уменьшает количество ошибок при обработке пользовательского ввода.
Однако приведение типов должно использоваться осознанно, поскольку
оно может скрывать некорректные входные данные. Например, строка
"123abc" может быть преобразована в число 123
в некоторых сценариях обработки вне строгих схем.
Одним из ключевых механизмов санитизации является удаление лишних
свойств, которые не описаны в схеме. Ajv поддерживает поведение через
параметр removeAdditional:
const ajv = new Ajv({
removeAdditional: "all"
});
Схема:
const schema = {
type: "object",
additionalProperties: false,
properties: {
username: { type: "string" }
}
};
Входные данные:
const data = {
username: "admin",
role: "superuser",
token: "abc123"
};
После валидации:
// результат
{ username: "admin" }
Варианты removeAdditional:
"all" — удаляет все дополнительные поля"failing" — удаляет только те, которые не прошли
валидациюfalse — не удаляет ничего (по умолчанию)Удаление дополнительных свойств особенно важно при работе с API, где входные данные могут содержать скрытые или потенциально вредоносные поля.
Санитизация часто включает автоматическую подстановку значений по
умолчанию. Ajv поддерживает это через опцию
useDefaults:
const ajv = new Ajv({
useDefaults: true
});
Схема:
const schema = {
type: "object",
properties: {
role: { type: "string", default: "user" },
active: { type: "boolean", default: true }
}
};
Вход:
const data = {};
Результат:
{
role: "user",
active: true
}
Механизм default-значений позволяет формировать полные структуры данных даже при частичном вводе, снижая необходимость дополнительных проверок на уровне бизнес-логики.
Сырые пользовательские данные часто содержат лишние пробелы,
управляющие символы или неконсистентное форматирование. Для этого
используется расширение через ajv-keywords, предоставляющее
дополнительные инструменты санитизации:
const Ajv = require("ajv");
const addKeywords = require("ajv-keywords");
const ajv = new Ajv();
addKeywords(ajv);
Пример использования трансформации строк:
const schema = {
type: "object",
properties: {
username: {
type: "string",
transform: ["trim", "toLowerCase"]
}
}
};
Входные данные:
{
username: " AdminUser "
}
Результат:
{
username: "adminuser"
}
Трансформации позволяют централизованно стандартизировать формат данных, исключая необходимость ручной обработки строк в прикладном коде.
Санитизация может быть связана не только с преобразованием, но и с фильтрацией. Ajv позволяет комбинировать строгую валидацию с очисткой структуры.
Пример схемы:
const schema = {
type: "object",
properties: {
email: { type: "string", format: "email" },
age: { type: "integer", minimum: 0 }
},
additionalProperties: false
};
При включённой строгой проверке любые некорректные данные будут
отклоняться, но при использовании комбинации с
removeAdditional и коэрцией можно добиться автоматического
приведения входа к допустимому виду.
Ajv позволяет расширять систему через пользовательские ключевые слова, что особенно полезно для сложной очистки данных:
ajv.addKeyword({
keyword: "sanitizeTrim",
type: "string",
modify: true,
compile: () => (data, dataPath, parentData, parentDataProperty) => {
if (typeof data === "string") {
parentData[parentDataProperty] = data.trim();
}
}
});
Использование в схеме:
const schema = {
type: "object",
properties: {
comment: {
type: "string",
sanitizeTrim: true
}
}
};
Такие механизмы позволяют внедрять произвольные правила очистки, например:
Санитизация особенно важна для сложных структур:
const schema = {
type: "object",
properties: {
user: {
type: "object",
properties: {
name: { type: "string", transform: ["trim"] },
contacts: {
type: "object",
properties: {
email: { type: "string", format: "email" }
},
additionalProperties: false
}
},
additionalProperties: false
}
}
};
При обработке вложенных объектов механизмы
removeAdditional, coerceTypes и
transform применяются рекурсивно, обеспечивая целостную
нормализацию всей структуры данных.
Санитизация не заменяет полноценную валидацию и не должна рассматриваться как единственный механизм защиты. Основные риски:
В системах с повышенными требованиями к безопасности часто разделяют этапы:
Такой подход снижает вероятность непредсказуемого поведения при обработке внешнего ввода.
Максимальный эффект достигается при одновременном использовании нескольких возможностей:
const ajv = new Ajv({
coerceTypes: true,
useDefaults: true,
removeAdditional: "all"
});
В сочетании со схемами это позволяет добиться автоматического приведения данных к строгой структуре без дополнительного кода:
Типичный поток санитизации в Ajv можно представить как последовательность:
coerceTypes)useDefaults)removeAdditional)transform keywords)Такая модель позволяет унифицировать входные данные до уровня, пригодного для бизнес-логики без дополнительных проверок на уровне приложения.