Механизмы санитизации входных данных в Joi
Санитизация в Joi представляет собой набор механизмов преобразования входных данных в предсказуемый, нормализованный и безопасный формат до или одновременно с их валидацией. В отличие от чистой проверки типов и ограничений, Joi активно модифицирует входной объект, устраняя избыточные или потенциально опасные значения и приводя данные к единому виду.
Одной из ключевых особенностей Joi является автоматическое приведение типов (coercion). Библиотека стремится преобразовать входные значения к ожидаемому типу схемы.
Пример преобразования строки в число:
import Joi from 'joi';
const schema = Joi.object({
age: Joi.number().integer()
});
const result = schema.validate({
age: '25'
});
console.log(result.value);
// { age: 25 }
Входная строка '25' автоматически преобразуется в число
25. Это снижает необходимость ручной предобработки данных
на уровне приложения.
Аналогично работают преобразования для булевых значений:
const schema = Joi.object({
isActive: Joi.boolean()
});
schema.validate({ isActive: 'true' }).value;
// { isActive: true }
Для строк Joi предоставляет встроенные методы нормализации, позволяющие привести текст к единому формату.
const schema = Joi.object({
username: Joi.string().trim()
});
schema.validate({ username: ' admin ' }).value;
// { username: 'admin' }
Метод trim() удаляет начальные и конечные пробелы,
предотвращая ошибки сравнения и поиска.
const schema = Joi.object({
email: Joi.string().lowercase()
});
schema.validate({ email: 'Test@Example.COM' }).value;
// { email: 'test@example.com' }
Метод lowercase() нормализует строку, что особенно важно
для email, идентификаторов и логинов.
Также доступен uppercase():
const schema = Joi.object({
code: Joi.string().uppercase()
});
schema.validate({ code: 'abc123' }).value;
// { code: 'ABC123' }
Санитизация часто включает заполнение отсутствующих данных корректными значениями.
const schema = Joi.object({
role: Joi.string().default('user')
});
schema.validate({}).value;
// { role: 'user' }
Значения по умолчанию позволяют устранять undefined и
обеспечивать стабильность структуры данных.
Также возможно использование вычисляемых значений:
const schema = Joi.object({
createdAt: Joi.date().default(() => new Date(), 'current date')
});
Одним из важных аспектов санитизации является контроль структуры объекта. Joi позволяет удалять поля, не описанные в схеме.
const schema = Joi.object({
username: Joi.string()
}).unknown(false);
const result = schema.validate({
username: 'admin',
role: 'superuser'
});
console.log(result.value);
// { username: 'admin' }
По умолчанию лишние поля могут быть либо запрещены, либо игнорированы в зависимости от настроек:
Joi.object({
username: Joi.string()
}).options({ stripUnknown: true });
В этом режиме все неизвестные ключи автоматически удаляются, что снижает риск обработки неожиданных данных.
Joi применяет правила рекурсивно ко всей структуре данных.
const schema = Joi.object({
user: Joi.object({
name: Joi.string().trim(),
email: Joi.string().lowercase()
})
});
schema.validate({
user: {
name: ' Ivan ',
email: 'IVAN@MAIL.COM'
}
}).value;
Результат:
{
user: {
name: 'Ivan',
email: 'ivan@mail.com'
}
}
Такая модель обеспечивает единообразие данных на всех уровнях вложенности.
Joi позволяет создавать собственные правила преобразования данных.
customconst schema = Joi.object({
tags: Joi.array().items(
Joi.string().custom((value) => value.trim().toLowerCase())
)
});
schema.validate({
tags: [' NodeJS ', ' JAVASCRIPT ']
}).value;
Результат:
{
tags: ['nodejs', 'javascript']
}
messages и комплексной логики трансформацииХотя messages не изменяет данные, он часто используется
совместно с кастомной логикой для контроля качества данных.
Санитизация массивов включает приведение элементов к единому виду и фильтрацию пустых значений.
const schema = Joi.object({
list: Joi.array().items(Joi.string().trim().lowercase())
});
schema.validate({
list: [' A ', ' B ', ' C ']
}).value;
Также возможно удаление пустых строк через кастомную обработку:
Joi.array().items(
Joi.string().trim().min(1)
).custom((arr) => arr.filter(Boolean));
Joi поддерживает динамическое изменение правил в зависимости от входных данных.
const schema = Joi.object({
type: Joi.string(),
value: Joi.when('type', {
is: 'number',
then: Joi.number().integer(),
otherwise: Joi.string().trim()
})
});
В этом случае санитизация value зависит от значения
type, что позволяет строить адаптивные схемы обработки
данных.
Санитизация в Joi часто используется как первый слой защиты от неожиданных или вредоносных входных данных.
Удаление неизвестных ключей:
const schema = Joi.object({
username: Joi.string(),
password: Joi.string()
}).prefs({ stripUnknown: true });
Игнорирование лишних данных предотвращает их дальнейшее распространение по системе, снижая поверхность атаки и вероятность логических ошибок.
Joi позволяет контролировать поведение пустых значений.
const schema = Joi.object({
nickname: Joi.string().empty('').default('anonymous')
});
В этом случае пустая строка будет преобразована в значение по умолчанию.
Санитизация часто применяется для обеспечения консистентного формата хранения данных:
Такая обработка позволяет унифицировать входной поток данных до попадания в бизнес-логику, минимизируя необходимость дополнительных проверок на последующих этапах обработки