React.js: основные проблемы безопасности

React.js, как популярный фреймворк для создания пользовательских интерфейсов, сталкивается с множеством проблем безопасности. Они разделяются на уязвимости в самом фреймворке, практики разработки и управление зависимостями.

Критические уязвимости в React Server Components (RSC)

В декабре 2025 года обнаружена критическая серия уязвимостей в React Server Components, которые требуют немедленного обновления.

CVE-2025-55182 (CVSS 10.0 — максимальный уровень серьезности) позволяет удаленное выполнение кода (RCE) на сервере через небезопасную десериализацию при обработке Flight протокола. Уязвимость не требует аутентификации и имеет надежность эксплуатации близкую к 100%. Активная эксплуатация в дикой природе начилась 5 декабря 2025 года, при этом атакующие развертывают крипто-майнеры, бэкдоры и украды облачных учетных данных.

Затронутые версии:

  • React: 19.0, 19.1, 19.2
  • Next.js: 15.x, 16.x (App Router), Canary начиная с 14.3.0

Обновитесь до версий 19.0.3, 19.1.4, 19.2.3 как можно скорее.

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

  • CVE-2025-55184 (CVSS 7.5) — отказ в обслуживании (DoS) через небезопасную десериализацию
  • CVE-2025-67779 — еще один вектор DoS в результате неполного патча

Проблемы базовой безопасности приложений

Cross-Site Scripting (XSS) атаки

XSS остается одной из наиболее распространенных проблем в React приложениях.

dangerouslySetInnerHTML

Использование dangerouslySetInnerHTML обходит встроенные защиты React от XSS. React автоматически экранирует строковые значения, но dangerouslySetInnerHTML передает байпасс этого механизма.

Небезопасно:

javascript// Уязвимо для XSS
<div dangerouslySetInnerHTML={{__html: userInput}} />

Правильный подход:

Используйте библиотеки для санитизации, такие как DOMPurify:

javascriptimport DOMPurify from 'dompurify';
const sanitizedInput = DOMPurify.sanitize(userInput);
<div dangerouslySetInnerHTML={{__html: sanitizedInput}} />

Защита по умолчанию

React защищает от XSS автоматически при использовании данных связывания в фигурных скобках {}. Это рекомендуемый метод:

javascript// Безопасно — React экранирует значение
<div>{userInput}</div>

Защита от CSRF (Cross-Site Request Forgery)

CSRF атаки особенно опасны для операций изменения состояния (POST, PUT, DELETE).

Рекомендуемая схема:

  1. Сервер генерирует уникальный CSRF токен для каждой сессии пользователя
  2. Токен хранится в httpOnly cookie
  3. Frontend запрашивает токен перед изменяющимися операциями
  4. Токен отправляется в заголовке запроса (не в cookie, которое браузер отправляет автоматически)
javascript// Получение CSRF токена
const response = await fetch('/api/csrf-token');
const { csrfToken } = await response.json();

// Использование в защищенном запросе
fetch('/api/transfer', {
  method: 'POST',
  headers: {
    'X-CSRF-Token': csrfToken,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ amount: 1000 })
});

Дополнительные меры:

  • Установите SameSite для cookies
  • Используйте подписанные токены
  • Проверяйте origin/referrer заголовки

Проблемы хранения аутентификационных данных

Хранение JWT и других чувствительных токенов требует тщательного выбора подхода.

localStorage/sessionStorage:

Преимущества:

  • Защита от CSRF (токен не отправляется автоматически)
  • Простоту реализации

Недостатки:

  • Доступны любому JavaScript на странице, включая зловредные скрипты из скомпрометированных зависимостей
  • Уязвимы для XSS атак

HttpOnly cookies:

Преимущества:

  • Недоступны для JavaScript
  • Браузер отправляет автоматически

Недостатки:

  • Уязвимы для CSRF (требует дополнительной защиты)
  • CSRF токены должны быть в отдельном, доступном для чтения cookie

Рекомендуемый подход:

Хранить refresh token в httpOnly cookie, а access token в памяти или sessionStorage с коротким временем жизни. Это балансирует безопасность и удобство.

Валидация и санитизация входных данных

Необходимо применять многоуровневый подход к валидации:

  1. Валидация типов и формата — проверка что данные соответствуют ожидаемому типу
  2. Санитизация — удаление или экранирование потенциально опасных символов
  3. Использование библиотек — например Zod для валидации, DOMPurify для HTML
javascriptimport { z } from 'zod';

const userSchema = z.object({
  email: z.string().email(),
  name: z.string().min(2).max(50)
});

// Валидация перед использованием
const userData = userSchema.parse(input);

JSON Injection и eval()

Никогда не используйте eval() для парсинга JSON.

Уязвимо:

javascriptvar result = eval("(" + json_string + ")"); // ОПАСНО!

Безопасно:

javascriptvar result = JSON.parse(json_string); // Правильно

JSON.parse() — это простой текстовый парсер, который не выполняет код.

Проблемы безопасности зависимостей (Supply Chain)

Уязвимости npm пакетов

npm представляет критическую поверхность атаки для React проектов.

В сентябре 2025 года скомпрометировано 18 основных пакетов (chalk, debug, ansi-styles и др.), загружаемых 2.6 млрд раз в неделю. Атакующие внедрили код, переписывающий криптовалютные транзакции перед подписью.

В ноябре 2025 обнаружена критическая уязвимость CVE-2025-11953 в React Native Community CLI, позволяющая удаленное выполнение кода на машинах разработчиков.

Защита:

  • Используйте package-lock.json при установке (npm ci вместо npm install)
  • Проверяйте версии хешей (избегайте SHA-1, используйте SHA-512)
  • Регулярно сканируйте на известные уязвимости: npm audit
  • Удаляйте неиспользуемые зависимости
  • Закрепляйте (pin) версии в production, особенно для критических пакетов

Prototype Pollution атаки

Prototype Pollution позволяет атакующему добавлять или модифицировать свойства глобального Object.prototype.

Это может привести к RCE, если используется в сочетании с другими уязвимостями.

Пример уязвивого кода:

javascriptconst merge = (target, source) => {
  for (let key in source) {
    target[key] = source[key]; // Опасно если key == "__proto__"
  }
  return target;
};

Правильный подход:

javascriptconst merge = (target, source) => {
  for (let key in source) {
    if (Object.prototype.hasOwnProperty.call(source, key)) {
      if (!key.startsWith('__') && key !== 'constructor' && key !== 'prototype') {
        target[key] = source[key];
      }
    }
  }
  return target;
};

Лучшие практики безопасности React приложений

1. Используйте встроенные защиты React

Полагайтесь на автоматическое экранирование через JSX синтаксис {} вместо ручного манипулирования DOM.

2. Избегайте опасных URL паттернов

Не используйте динамические URL протоколы без валидации:

javascript// Уязвимо
<a href={userUrl}>Link</a>

// Правильно
const isValidUrl = (url) => {
  try {
    const u = new URL(url);
    return ['http:', 'https:'].includes(u.protocol);
  } catch {
    return false;
  }
};
<a href={isValidUrl(userUrl) ? userUrl : '#'}>Link</a>

3. Защита Server-Side Rendering (SSR)

При использовании SSR с dangerouslySetInnerHTML, всегда санитизируйте контент, даже если он поступает с сервера.

4. Настройка ESLint для безопасности

Используйте конфигурацию ESLint React Security для автоматического обнаружения уязвимостей:

bashnpm install --save-dev eslint-plugin-react eslint-plugin-security

5. Code Splitting и Lazy Loading

Загружайте компоненты по требованию для уменьшения поверхности атаки в начальном бандле:

javascriptconst Dashboard = React.lazy(() => import('./Dashboard'));

function App() {
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <Dashboard />
    </Suspense>
  );
}

6. Content Security Policy (CSP)

Установите строгую CSP для защиты от XSS:

xml<meta http-equiv="Content-Security-Policy" 
      content="default-src 'self'; script-src 'self' 'nonce-xyz123'">

7. Мониторинг и логирование безопасности

Логируйте отклоненные входные данные и подозрительную активность для раннего обнаружения атак.

Итоговый чек-лист безопасности

  • Обновитесь до последних версий React (19.0.3+, 19.1.4+, 19.2.3+)
  • Санитизируйте все пользовательские входные данные
  • Используйте CSRF токены для операций изменения состояния
  • Правильно храните аутентификационные токены (httpOnly cookies + CSRF защита)
  • Регулярно проверяйте npm зависимости (npm audit)
  • Избегайте eval() и dangerouslySetInnerHTML без необходимости
  • Реализуйте Content Security Policy
  • Используйте HTTPS для всех коммуникаций
  • Проводите регулярные security code reviews
  • Мониторьте и логируйте подозрительную активность

React обеспечивает базовую защиту от XSS через автоматическое экранирование, но разработчики должны дополнить это многоуровневым подходом к безопасности, учитывая тот факт, что фреймворк сам по себе уязвим для серьезных проблем, особенно в RSC компонентах.

Оцените статью
( Пока оценок нет )
hyper/blog