Инъекции возникают в ситуациях, когда пользовательские данные попадают в интерпретируемый контекст без предварительной проверки и очистки. Наиболее распространённые разновидности:
Библиотека Validator.js предназначена для проверки и санитарной обработки строковых данных. Она не заменяет параметризованные запросы, ORM, экранирование или Content Security Policy, однако значительно снижает риск передачи вредоносных значений в опасные участки приложения.
Validator.js особенно полезен на этапе:
npm install validator
const validator = require('validator');
import validator fr om 'validator';
Validator.js используется как дополнительный уровень защиты. Безопасная архитектура строится на нескольких правилах:
Одна из ключевых ошибок — попытка запрещать «опасные» символы. Гораздо безопаснее разрешать только допустимые значения.
const input = req.body.username;
if (!input.includes("'")) {
// опасно
}
Подобная проверка легко обходится.
import validator fr om 'validator';
const username = req.body.username;
if (!validator.isAlphanumeric(username, 'en-US')) {
throw new Error('Недопустимое имя пользователя');
}
Разрешаются только буквы и цифры.
Ограничение размера ввода помогает предотвратить:
if (!validator.isLength(password, {
min: 8,
max: 64
})) {
throw new Error('Некорректная длина пароля');
}
const query = `
SEL ECT * FR OM users
WH ERE email = '${email}'
`;
Если пользователь введёт:
' OR 1=1 --
запрос станет компрометированным.
if (!validator.isEmail(email)) {
throw new Error('Некорректный email');
}
if (!validator.isUUID(userId)) {
throw new Error('Некорректный ID');
}
if (!validator.isInt(age.toString())) {
throw new Error('Возраст должен быть числом');
}
Validator.js не предотвращает SQL Injection самостоятельно.
Правильный вариант:
const query = `
SEL ECT * FR OM users
WH ERE email = ?
`;
db.execute(query, [email]);
NoSQL Injection часто встречается в MongoDB при передаче объектов вместо строк.
User.findOne({
login: req.body.login,
password: req.body.password
});
Атакующий может передать:
{
"login": {
"$ne": null
}
}
if (!validator.isString(req.body.login)) {
throw new Error('Некорректный логин');
}
Однако в Validator.js отсутствует метод isString. Обычно
используют:
if (typeof req.body.login !== 'string') {
throw new Error('Ожидалась строка');
}
После этого:
const login = validator.trim(req.body.login);
if (!validator.isAlphanumeric(login)) {
throw new Error('Недопустимый логин');
}
Validator.js содержит набор sanitizer-функций.
Удаляет пробелы по краям.
const login = validator.trim(req.body.login);
Преобразует HTML-символы в безопасные сущности.
const comment = validator.escape(req.body.comment);
Ввод:
<script>alert(1)</script>
После обработки:
<script>alert(1)</script>
Удаляет управляющие ASCII-символы.
const clean = validator.stripLow(input);
Полезно против скрытых payload и бинарных вставок.
Удаляет символы из чёрного списка.
const sanitized = validator.blacklist(input, '<>"');
Оставляет только разрешённые символы.
const safe = validator.whitelist(input, 'a-zA-Z0-9');
Это значительно безопаснее blacklist-подхода.
exec(`ping ${host}`);
Пользователь может передать:
127.0.0.1 && rm -rf /
if (!validator.isIP(host) &&
!validator.isFQDN(host)) {
throw new Error('Некорректный адрес');
}
const safeHost = validator.whitelist(
host,
'a-zA-Z0-9.-'
);
Даже после валидации необходимо избегать shell-интерпретации.
exec(`ping ${host}`);
spawn('ping', [host]);
Validator.js не является полноценной XSS-защитой, но помогает снизить риски.
const safeText = validator.escape(userInput);
const nickname = validator.whitelist(
userInput,
'a-zA-Zа-яА-Я0-9_'
);
if (!validator.isURL(url, {
protocols: ['https'],
require_protocol: true
})) {
throw new Error('Некорректный URL');
}
Это уменьшает риск передачи:
jav * ascript:alert(1)
Почтовые заголовки могут быть атакованы через CRLF-инъекции.
if (!validator.isEmail(email)) {
throw new Error('Некорректный email');
}
const safeEmail = validator.stripLow(email);
Нормализация помогает избежать обхода проверок.
const normalized = validator.normalizeEmail(email);
USER@GMAIL.COM
Преобразуется в:
user@gmail.com
При работе с JSON важно проверять структуру и содержимое.
if (!validator.isJSON(data)) {
throw new Error('Некорректный JSON');
}
if (!validator.isLength(data, {
max: 5000
})) {
throw new Error('Слишком большой JSON');
}
UUID часто используется в URL, API и базе данных.
if (!validator.isUUID(id)) {
throw new Error('Некорректный UUID');
}
Это предотвращает передачу:
1 OR 1=1
вместо идентификатора.
if (!validator.isIP(ip)) {
throw new Error('Некорректный IP');
}
if (!validator.isFQDN(domain)) {
throw new Error('Некорректный домен');
}
validator.isURL(url, {
protocols: ['https'],
require_protocol: true,
require_valid_protocol: true,
allow_underscores: false,
allow_trailing_dot: false
});
validator.isInt(page.toString(), {
min: 1,
max: 1000
});
validator.isFloat(price.toString(), {
min: 0,
max: 100000
});
import validator fr om 'validator';
function validateLogin(data) {
if (typeof data.email !== 'string') {
throw new Error('Некорректный email');
}
if (typeof data.password !== 'string') {
throw new Error('Некорректный пароль');
}
const email = validator.normalizeEmail(
validator.trim(data.email)
);
const password = validator.trim(data.password);
if (!validator.isEmail(email)) {
throw new Error('Некорректный email');
}
if (!validator.isLength(password, {
min: 8,
max: 128
})) {
throw new Error('Некорректный пароль');
}
if (validator.contains(password, '<script>')) {
throw new Error('Подозрительный пароль');
}
return {
email,
password
};
}
function sanitizeComment(comment) {
let result = validator.trim(comment);
result = validator.stripLow(result);
result = validator.escape(result);
return result;
}
const phone = validator.whitelist(
input,
'0-9+()- '
);
const username = validator.whitelist(
input,
'a-zA-Z0-9_'
);
Validator.js не умеет валидировать JWT полностью, однако может проверять формат.
const tokenPattern =
/^[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+$/;
if (!tokenPattern.test(token)) {
throw new Error('Некорректный токен');
}
Некоторые атаки используют Unicode-обходы и невидимые символы.
const clean = validator.stripLow(input, true);
const lim it = req.query.limit;
if (!validator.isInt(limit, {
min: 1,
max: 100
})) {
throw new Error('Некорректный limit');
}
ORDER BY ${sort}
const allowed = ['name', 'date', 'price'];
if (!allowed.includes(sort)) {
throw new Error('Недопустимое поле сортировки');
}
Validator.js не заменяет:
validator.blacklist(input, '<>"\'');
validator.whitelist(input, 'a-zA-Z0-9');
Validator.js ориентирован на строки.
Перед использованием необходимо проверять тип:
if (typeof input !== 'string') {
throw new Error('Ожидалась строка');
}
escape() полезен для HTML-контекста, но не защищает:
Validator.js эффективен как часть layered security-подхода.
Типичная цепочка защиты:
import validator from 'validator';
function sanitizeUserInput(data) {
if (typeof data.username !== 'string') {
throw new Error('Некорректный username');
}
let username = validator.trim(data.username);
username = validator.whitelist(
username,
'a-zA-Z0-9_'
);
if (!validator.isLength(username, {
min: 3,
max: 20
})) {
throw new Error('Некорректная длина username');
}
return username;
}
function validateEmail(req, res, next) {
const email = req.body.email;
if (typeof email !== 'string') {
return res.status(400).json({
error: 'Некорректный email'
});
}
const normalized =
validator.normalizeEmail(
validator.trim(email)
);
if (!validator.isEmail(normalized)) {
return res.status(400).json({
error: 'Некорректный email'
});
}
req.body.email = normalized;
next();
}
Validator.js обычно используется вместе с:
Библиотека показывает высокую эффективность при: