Безопасная работа с Query String

Page.js — это легковесная библиотека для клиентской маршрутизации на стороне браузера, позволяющая строить одностраничные приложения с поддержкой истории навигации. Одним из ключевых аспектов маршрутизации является обработка Query String — параметров, передаваемых в URL после знака ?. Правильная и безопасная работа с ними важна для корректного поведения приложения и предотвращения потенциальных уязвимостей.


Получение Query String в обработчиках маршрутов

Page.js предоставляет возможность определять маршруты с параметрами и работать с объектом ctx в функции-обработчике. Объект ctx содержит информацию о текущем маршруте, включая Query String.

Пример базового маршрута с Query String:

page('/search', function(ctx) {
    console.log(ctx.querystring); // raw query string: "q=javascript&page=2"
});

Здесь ctx.querystring возвращает строку после ? без декодирования. Для работы с параметрами удобно использовать стандартный объект URLSearchParams.

page('/search', function(ctx) {
    const params = new URLSearchParams(ctx.querystring);
    const query = params.get('q');   // "javascript"
    const pageNum = params.get('page'); // "2"
});

Использование URLSearchParams позволяет безопасно извлекать параметры без необходимости ручного парсинга строки, что снижает риск ошибок и уязвимостей.


Построение безопасных URL с параметрами

Для генерации ссылок с Query String важно избегать ручной конкатенации строк, чтобы не допустить инъекций или некорректного кодирования. Page.js не занимается автоматическим кодированием, поэтому необходимо использовать encodeURIComponent:

const query = 'JavaScript & Page.js';
const pageNum = 2;

const url = `/search?q=${encodeURIComponent(query)}&page=${encodeURIComponent(pageNum)}`;
page(url);

Такой подход предотвращает проблемы с символами &, = и другими специальными символами в URL.


Извлечение параметров в динамических маршрутах

Page.js позволяет создавать динамические сегменты URL, например /user/:id. При необходимости сочетать динамические сегменты с Query String, значения параметров хранятся в ctx.params, а Query String — в ctx.querystring.

page('/user/:id', function(ctx) {
    const userId = ctx.params.id; // значение из сегмента URL
    const params = new URLSearchParams(ctx.querystring);
    const tab = params.get('tab'); // значение параметра tab
});

Такое разделение помогает структурировать данные маршрута, снижая вероятность смешения динамических сегментов и Query String.


Валидация параметров

Query String может быть источником ненадежных данных, особенно если URL формируется пользователем. Для безопасной работы рекомендуется:

  1. Проверять наличие ожидаемых параметров:
if (!params.has('q')) {
    page.redirect('/search?q=default');
}
  1. Ограничивать длину и тип данных:
const pageNum = parseInt(params.get('page'), 10);
if (isNaN(pageNum) || pageNum < 1) {
    pageNum = 1;
}
  1. Фильтровать специальные символы для предотвращения XSS при вставке параметров в DOM:
const safeQuery = query.replace(/</g, "&lt;").replace(/>/g, "&gt;");

Обновление Query String без перезагрузки страницы

Page.js позволяет изменять маршрут и Query String без полной перезагрузки через page.show:

const params = new URLSearchParams();
params.set('q', 'Page.js');
params.set('page', 3);

page.show(`/search?${params.toString()}`);

Использование URLSearchParams.toString() гарантирует корректное кодирование параметров и совместимость с различными браузерами.


Парсинг Query String при загрузке страницы

Если приложение использует прямые переходы по URL (например, при F5 или внешней ссылке), нужно уметь извлекать параметры на этапе инициализации:

page('*', function(ctx) {
    const params = new URLSearchParams(ctx.querystring);
    // глобальная обработка параметров
});

Использование маршрута '*' позволяет захватывать все URL и работать с Query String до передачи управления специфическим маршрутам.


Советы по безопасности

  • Никогда не вставлять значения Query String напрямую в HTML без экранирования.
  • Ограничивать длину параметров и проверять их тип.
  • Использовать encodeURIComponent для генерации ссылок.
  • Валидация на клиенте не заменяет серверную проверку — любые данные из Query String должны быть безопасно обработаны и на сервере.

Итоговая структура безопасной работы с Query String

  1. Извлечение параметров через URLSearchParams(ctx.querystring).
  2. Разделение динамических сегментов (ctx.params) и Query String (ctx.querystring).
  3. Безопасная генерация URL с encodeURIComponent или URLSearchParams.toString().
  4. Валидация и фильтрация параметров перед использованием.
  5. Возможность изменения Query String без перезагрузки через page.show.

Эти практики обеспечивают корректное и безопасное взаимодействие с Query String в одностраничных приложениях на Page.js, минимизируя ошибки и уязвимости.