Безопасность маршрутизации

При работе с Universal Router важно понимать, что маршрутизация — это не только управление URL и обработка переходов, но и потенциальная точка уязвимости приложения. Маршруты напрямую влияют на доступ к ресурсам, поэтому некорректная конфигурация может привести к утечке данных или обходу авторизации.

Ключевые аспекты безопасности:

  • Контроль доступа: каждый маршрут должен проверять, имеет ли пользователь права на выполнение действия или просмотр ресурса. Отсутствие проверки может позволить неавторизованным пользователям получить доступ к защищённым страницам.
  • Валидация параметров маршрута: данные, получаемые из URL (например, /user/:id), нельзя использовать напрямую в запросах к базе данных или API. Все параметры необходимо тщательно проверять и экранировать.
  • Защита от XSS и инъекций: при динамической генерации контента на основе URL параметры маршрута не должны вставляться напрямую в HTML без экранирования.

Проверка авторизации в маршрутах

Universal Router предоставляет возможность использовать асинхронные функции для обработки маршрутов, что удобно для проверки прав доступа перед рендерингом страницы.

Пример:

import UniversalRouter from 'universal-router';

const routes = [
  {
    path: '/admin',
    action: async (context) => {
      if (!context.user || !context.user.isAdmin) {
        throw new Error('Доступ запрещён');
      }
      return 'Административная панель';
    }
  },
  {
    path: '/profile/:id',
    action: async ({ params, user }) => {
      if (!user) throw new Error('Необходимо авторизоваться');
      if (params.id !== user.id) throw new Error('Доступ к чужому профилю запрещён');
      return `Профиль пользователя ${params.id}`;
    }
  }
];

const router = new UniversalRouter(routes);

В данном примере проверяется, что пользователь авторизован и имеет соответствующие права, прежде чем разрешить доступ к содержимому маршрута.

Обработка ошибок и безопасное редиректирование

Маршруты должны корректно обрабатывать ошибки, чтобы пользователь не мог получить стек вызовов или внутреннюю информацию приложения. Рекомендуется использовать централизованный обработчик ошибок:

router.resolve('/admin').catch(error => {
  if (error.message === 'Доступ запрещён') {
    window.location.href = '/login';
  } else {
    console.error(error);
    window.location.href = '/error';
  }
});

Принципы безопасного редиректирования:

  • Использовать только внутренние URL.
  • Не допускать передачу внешних ссылок через параметры маршрута.
  • В случае ошибки всегда перенаправлять на страницы с минимальной чувствительной информацией.

Защита параметров маршрута

URL-параметры и query-параметры должны рассматриваться как потенциально небезопасные данные. Важно применять:

  • Фильтрацию и регулярные выражения: ограничение формата :id(\d+) предотвращает передачу строк вместо чисел.
  • Санитизацию: удаление специальных символов перед использованием в шаблонах или запросах.
  • Типизацию: использование строгих типов, например, через TypeScript или схемы валидации.

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

{
  path: '/user/:id(\\d+)',
  action: ({ params }) => {
    const userId = Number(params.id);
    if (isNaN(userId)) throw new Error('Некорректный идентификатор пользователя');
    return `Профиль пользователя ${userId}`;
  }
}

Ограничение глубины маршрутов и вложенных вызовов

Сложные вложенные маршруты повышают риск обхода логики безопасности. В Universal Router можно использовать вложенные маршруты, но каждый уровень должен проверять доступ:

{
  path: '/dashboard',
  children: [
    {
      path: 'settings',
      action: ({ user }) => {
        if (!user.isAdmin) throw new Error('Доступ запрещён');
        return 'Настройки';
      }
    }
  ]
}

Логирование и аудит

Для повышения безопасности рекомендуется логировать все попытки доступа к защищённым маршрутам. Это позволяет отслеживать потенциальные атаки и некорректные обращения:

router.resolve('/admin').catch(error => {
  console.log(`Попытка доступа к /admin: ${error.message}`);
});

Использование middleware-подхода

Хотя Universal Router не имеет встроенной системы middleware, можно создать обёртку для маршрутов, которая будет проверять авторизацию и параметры до выполнения основного действия:

function authWrapper(action) {
  return async (context) => {
    if (!context.user) throw new Error('Необходимо авторизоваться');
    return action(context);
  };
}

const routes = [
  { path: '/profile', action: authWrapper(({ user }) => `Профиль ${user.id}`) }
];

Такой подход позволяет централизованно управлять безопасностью без дублирования кода.

Итоговые рекомендации по безопасности

  • Всегда проверять права доступа на каждом маршруте.
  • Никогда не доверять данным из URL без валидации и санитизации.
  • Обрабатывать все ошибки безопасно, не раскрывая внутреннюю информацию.
  • Использовать строгие регулярные выражения и типизацию для параметров.
  • Логировать попытки доступа и подозрительную активность.
  • Рассматривать создание обёрток или middleware для унификации проверок безопасности.

Эти практики помогут сделать маршрутизацию в Universal Router безопасной и устойчивой к типовым атакам на клиентские и серверные приложения.