Предотвращение инъекций

Инъекции возникают в ситуациях, когда пользовательские данные попадают в интерпретируемый контекст без предварительной проверки и очистки. Наиболее распространённые разновидности:

  • SQL Injection
  • NoSQL Injection
  • Command Injection
  • LDAP Injection
  • HTML/JS Injection
  • Header Injection

Библиотека Validator.js предназначена для проверки и санитарной обработки строковых данных. Она не заменяет параметризованные запросы, ORM, экранирование или Content Security Policy, однако значительно снижает риск передачи вредоносных значений в опасные участки приложения.

Validator.js особенно полезен на этапе:

  • проверки пользовательского ввода;
  • фильтрации недопустимых символов;
  • нормализации данных;
  • удаления потенциально опасных конструкций;
  • строгой типизации строковых значений.

Установка Validator.js

Установка через npm

npm install validator

Подключение

CommonJS

const validator = require('validator');

ES Modules

import validator fr om 'validator';

Основные принципы защиты от инъекций

Validator.js используется как дополнительный уровень защиты. Безопасная архитектура строится на нескольких правилах:

  1. Никогда не доверять пользовательскому вводу.
  2. Валидировать данные по белому списку.
  3. Ограничивать длину строк.
  4. Удалять управляющие и опасные символы.
  5. Использовать параметризованные запросы.
  6. Не формировать команды и запросы конкатенацией строк.

Белые списки вместо чёрных списков

Одна из ключевых ошибок — попытка запрещать «опасные» символы. Гораздо безопаснее разрешать только допустимые значения.

Небезопасный подход

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('Недопустимое имя пользователя');
}

Разрешаются только буквы и цифры.


Проверка длины строк

Ограничение размера ввода помогает предотвратить:

  • буферные атаки;
  • переполнение;
  • чрезмерную нагрузку;
  • попытки внедрения длинных payload.

Использование isLength

if (!validator.isLength(password, {
    min: 8,
    max: 64
})) {
    throw new Error('Некорректная длина пароля');
}

Предотвращение SQL Injection

Типичная уязвимость

const query = `
    SEL ECT * FR OM users
    WH ERE email = '${email}'
`;

Если пользователь введёт:

' OR 1=1 --

запрос станет компрометированным.


Validator.js как первый уровень защиты

Проверка email

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

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-функций.

trim

Удаляет пробелы по краям.

const login = validator.trim(req.body.login);

escape

Преобразует HTML-символы в безопасные сущности.

const comment = validator.escape(req.body.comment);

Пример

Ввод:

<script>alert(1)</script>

После обработки:

&lt;script&gt;alert(1)&lt;/script&gt;

stripLow

Удаляет управляющие ASCII-символы.

const clean = validator.stripLow(input);

Полезно против скрытых payload и бинарных вставок.


blacklist

Удаляет символы из чёрного списка.

const sanitized = validator.blacklist(input, '<>"');

whitelist

Оставляет только разрешённые символы.

const safe = validator.whitelist(input, 'a-zA-Z0-9');

Это значительно безопаснее blacklist-подхода.


Защита от Command Injection

Уязвимый код

exec(`ping ${host}`);

Пользователь может передать:

127.0.0.1 && rm -rf /

Проверка hostname

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]);

Предотвращение XSS

Validator.js не является полноценной XSS-защитой, но помогает снизить риски.


Экранирование HTML

const safeText = validator.escape(userInput);

Ограничение допустимых символов

const nickname = validator.whitelist(
    userInput,
    'a-zA-Zа-яА-Я0-9_'
);

Проверка URL

if (!validator.isURL(url, {
    protocols: ['https'],
    require_protocol: true
})) {
    throw new Error('Некорректный URL');
}

Это уменьшает риск передачи:

jav * ascript:alert(1)

Проверка email против Header Injection

Почтовые заголовки могут быть атакованы через CRLF-инъекции.

Проверка email

if (!validator.isEmail(email)) {
    throw new Error('Некорректный email');
}

Удаление управляющих символов

const safeEmail = validator.stripLow(email);

Нормализация данных

Нормализация помогает избежать обхода проверок.

normalizeEmail

const normalized = validator.normalizeEmail(email);

Пример

USER@GMAIL.COM

Преобразуется в:

user@gmail.com

Валидация JSON-полей

При работе с JSON важно проверять структуру и содержимое.

Проверка JSON

if (!validator.isJSON(data)) {
    throw new Error('Некорректный JSON');
}

Ограничение размера JSON

if (!validator.isLength(data, {
    max: 5000
})) {
    throw new Error('Слишком большой JSON');
}

Валидация UUID

UUID часто используется в URL, API и базе данных.

Проверка UUID

if (!validator.isUUID(id)) {
    throw new Error('Некорректный UUID');
}

Это предотвращает передачу:

1 OR 1=1

вместо идентификатора.


Валидация IP-адресов

if (!validator.isIP(ip)) {
    throw new Error('Некорректный IP');
}

Валидация доменных имён

if (!validator.isFQDN(domain)) {
    throw new Error('Некорректный домен');
}

Валидация URL

Безопасная конфигурация

validator.isURL(url, {
    protocols: ['https'],
    require_protocol: true,
    require_valid_protocol: true,
    allow_underscores: false,
    allow_trailing_dot: false
});

Проверка числовых параметров

isInt

validator.isInt(page.toString(), {
    min: 1,
    max: 1000
});

isFloat

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;
}

Использование whitelist для строгой фильтрации

Телефонный номер

const phone = validator.whitelist(
    input,
    '0-9+()- '
);

Имя пользователя

const username = validator.whitelist(
    input,
    'a-zA-Z0-9_'
);

Проверка JWT и токенов

Validator.js не умеет валидировать JWT полностью, однако может проверять формат.

Base64-подобная структура

const tokenPattern =
    /^[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+$/;

if (!tokenPattern.test(token)) {
    throw new Error('Некорректный токен');
}

Ограничение Unicode-символов

Некоторые атаки используют Unicode-обходы и невидимые символы.

Удаление скрытых символов

const clean = validator.stripLow(input, true);

Проверка данных API

Безопасная обработка query-параметров

const lim it = req.query.limit;

if (!validator.isInt(limit, {
    min: 1,
    max: 100
})) {
    throw new Error('Некорректный limit');
}

Безопасная обработка sort

Небезопасно

ORDER BY ${sort}

Безопасно

const allowed = ['name', 'date', 'price'];

if (!allowed.includes(sort)) {
    throw new Error('Недопустимое поле сортировки');
}

Типичные ошибки при использовании Validator.js

Попытка заменить валидацией экранирование

Validator.js не заменяет:

  • prepared statements;
  • ORM;
  • CSP;
  • escaping;
  • sandboxing.

Использование blacklist вместо whitelist

Плохо

validator.blacklist(input, '<>"\'');

Лучше

validator.whitelist(input, 'a-zA-Z0-9');

Отсутствие проверки типа

Validator.js ориентирован на строки.

Перед использованием необходимо проверять тип:

if (typeof input !== 'string') {
    throw new Error('Ожидалась строка');
}

Избыточное доверие escape

escape() полезен для HTML-контекста, но не защищает:

  • SQL;
  • shell-команды;
  • MongoDB-запросы;
  • LDAP;
  • файловую систему.

Стратегия многоуровневой защиты

Validator.js эффективен как часть layered security-подхода.

Типичная цепочка защиты:

  1. Проверка типа данных.
  2. Ограничение длины.
  3. Нормализация.
  4. whitelist-фильтрация.
  5. Санитарная обработка.
  6. Параметризованные запросы.
  7. Экранирование на уровне шаблонизатора.
  8. CSP и HTTP security headers.
  9. Логирование подозрительных запросов.
  10. Rate limiting.

Практический пример безопасной обработки данных

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;
}

Интеграция с Express Middleware

Middleware валидации

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 с другими механизмами защиты

Validator.js обычно используется вместе с:

  • Helmet
  • DOMPurify
  • express-validator
  • Joi
  • Zod
  • ORM
  • CSP
  • rate limiter
  • WAF

Когда Validator.js особенно полезен

Библиотека показывает высокую эффективность при:

  • обработке форм;
  • проверке query-параметров;
  • фильтрации API-ввода;
  • защите REST API;
  • обработке email;
  • нормализации URL;
  • валидации UUID;
  • очистке HTML-данных;
  • защите административных панелей;
  • фильтрации пользовательского контента.