Санитизация входных данных

Sanitization (санитизация) — процесс очистки и приведения данных, получаемых от пользователя, к безопасной и ожидаемой форме перед их обработкой в маршрутизаторе. В Page.js, как в любой клиентской библиотеке маршрутизации, особенно важно учитывать, что путь URL и параметры запроса могут содержать непредусмотренные или вредоносные данные.

Принцип строгого контроля: Page.js получает URL через объект location браузера, и эти строки могут содержать любые символы, включая спецсимволы (<, >, "), код JS или SQL-подобные конструкции. Неправильная обработка таких данных может привести к XSS-уязвимостям или некорректной маршрутизации.


Санитизация маршрутов

Маршруты Page.js определяются с помощью функции page(path, callback). Чтобы исключить потенциальные ошибки, важно:

  1. Использовать строгие шаблоны путей Вместо обобщённых * или :param* лучше задавать конкретные регулярные выражения для параметров:

    page('/user/:id(\\d+)', ctx => {
        console.log(ctx.params.id); // только числа
    });
  2. Очистка параметров URL Любые значения параметров должны быть обработаны функциями вроде decodeURIComponent, но с последующей проверкой на допустимые символы:

    const id = decodeURIComponent(ctx.params.id);
    if (!/^\d+$/.test(id)) {
        page.redirect('/error');
    }
  3. Фильтрация query-параметров Поскольку Page.js может использовать ctx.querystring, важно преобразовывать параметры в безопасный вид:

    function parseQuery(query) {
        const params = new URLSearchParams(query);
        const result = {};
        for (const [key, value] of params.entries()) {
            result[key] = value.replace(/[<>"'`;]/g, '');
        }
        return result;
    }
    
    const queryParams = parseQuery(ctx.querystring);

Санитизация пользовательских ссылок

При динамическом формировании ссылок через page.show или прямую подстановку в href:

  • Удалять подозрительные символы: символы <, >, " могут вызвать XSS при рендеринге.

  • Нормализовать путь: использовать encodeURI или encodeURIComponent для безопасного включения параметров в URL:

    const safePath = '/user/' + encodeURIComponent(userId);
    page.show(safePath);
  • Избегать прямой подстановки HTML: значения из ctx.params или query-параметров нельзя вставлять в HTML без экранирования.


Проверка и фильтрация данных

Sanitization — это не только удаление опасных символов, но и проверка соответствия данных ожидаемому типу:

  • Строки: проверка длины, отсутствие управляющих символов и тегов.
  • Числа: убедиться, что параметр действительно является числом.
  • Списки и массивы: фильтровать элементы по допустимому набору значений.

Пример проверки числового параметра:

const userId = parseInt(ctx.params.id, 10);
if (isNaN(userId) || userId <= 0) {
    page.redirect('/404');
}

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

Page.js поддерживает цепочку middleware, что позволяет создавать один слой для всех маршрутов, обрабатывающий входные данные:

function sanitizeParams(ctx, next) {
    for (const key in ctx.params) {
        ctx.params[key] = ctx.params[key].replace(/[<>"'`;]/g, '');
    }
    next();
}

page('*', sanitizeParams);

Такой подход упрощает поддержку и снижает вероятность пропуска потенциально опасного значения.


Рекомендации по безопасности

  1. Не доверять параметрам URL — любые значения должны считаться потенциально опасными.
  2. Комбинировать валидацию и санитизацию — проверка формата и удаление опасных символов.
  3. Использовать регулярные выражения для параметров — предотвращает попадание неожиданных значений в приложение.
  4. Обрабатывать query-параметры через URLSearchParams — упрощает работу и предотвращает ошибки парсинга.
  5. Избегать вставки данных в HTML без экранирования — особенно актуально для SPA и динамически обновляемых блоков.

Примеры комплексной санитизации

page('/product/:id(\\d+)', ctx => {
    const productId = parseInt(ctx.params.id, 10);
    if (isNaN(productId)) {
        page.redirect('/404');
        return;
    }

    const safeQuery = {};
    const params = new URLSearchParams(ctx.querystring);
    for (const [key, value] of params.entries()) {
        safeQuery[key] = value.replace(/[^a-zA-Z0-9-_]/g, '');
    }

    renderProductPage(productId, safeQuery);
});

Этот пример сочетает проверку формата маршрута, преобразование параметров в числа, очистку query-параметров и безопасный рендер. Такой подход минимизирует риски XSS, некорректной маршрутизации и потенциальных ошибок при работе с Page.js.