Как защитить React-фронтенд перед выходом в продакшен

Sat Aug 29 2026

Как защитить React-фронтенд перед выходом в продакшен

А 3 декабря 2025 года React опубликовал критическое уведомление о безопасности React Server Components, GHSA-fv66-9v8q-g76r. Исправьте границу фреймворка и продолжайте использовать React.

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

При этом экранирование JSX в React даёт полезную базовую точку для проверки безопасности.

Вы проверите модель рендеринга React, видимые браузеру секреты, хранение токенов и OAuth. Также вы проверите зависимости и заголовки развёрнутого приложения. Затем вы получите критерии выпуска, основанные на блокирующих проблемах фактического production-артефакта.

В этой статье

React безопасен для использования; граница вашего приложения всё ещё требует подтверждения

Документация React говорит: «Каждый коммит React тестируется на критически важных для бизнеса поверхностях с более чем миллиардом пользователей. Более 100 000 компонентов React в Meta помогают проверять каждую стратегию миграции». Это полезное свидетельство зрелости библиотеки. Это не одобрение приложения.

Ваш код управляет непроверенным HTML. Ваша сборка управляет конфигурацией, отправляемой браузеру. Ваш API управляет доступом к счетам. Зависимости выполняются во время установки и работы. Ваша hosting-платформа устанавливает заголовки, которые получают браузеры.

Практический вопрос заключается в том, использует ли ваша сборка RSC, Server Functions или другую затронутую интеграцию. Если да, проверьте применимые исправленные версии перед одобрением выпуска. Если поставляется только клиентский bundle, перечисленные уведомления RSC и Server Functions обычно не описывают этот браузерный bundle; проверьте, запускает ли ваш фреймворк всё ещё затронутые серверные компоненты в продакшене.

Обычный чеклист React организован плохо. В нём смешаны раскрытие данных в браузере, авторизация API и поведение на мобильных устройствах, как будто это одна проблема. Это разные границы, с разными ответственными и разными тестами.

React защищает некоторые пути рендеринга. Он не защищает секреты вашего приложения, модель авторизации, цепочку поставок пакетов или развёртывание.

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

Начните с проверки трёх поверхностей:

ПоверхностьЧто существует на этой границеЧто должна проверять проверка выпуска
Контент, отрендеренный ReactОбычная интерполяция JSX экранирует значения в соответствии с правилами рендеринга ReactHTML-приёмники, небезопасные схемы URL, динамическое выполнение кода
Приложение, раскрытое браузеруБраузер запускает bundle и выполняет сетевые запросыBundle, source maps, переменные окружения, хранилище, URL, токены, персональные данные
Серверный и доставочный слойВаш сервер и платформа могут хранить секреты и обеспечивать контроль доступаАвторизация API, лимиты запросов, версии RSC/Server Functions, install-скрипты, HTTPS, CSP, заголовки

Эта модель разделяет ответственность. Браузер может отображать состояние авторизации; он не может сохранять значение конфиденциальным после его получения. Ваш сервер может защищать ключ провайдера; он всё равно должен авторизовать каждый запрос.

OWASP Bullet-proof React — это Incubator Project версии 0.0.0. Используйте его как полезную подборку рекомендаций, а не как сертификацию или завершённую структуру одобрения. Ваши критерии должны указывать свидетельства для каждого риска.

Страница проекта OWASP в настоящее время указывает Top 10:2025 как текущий выпуск. С осторожностью относитесь к страницам, рекламирующим отдельный выпуск 2026 года; обсуждение Security Boulevard также сообщает, что нового OWASP Top 10 на 2026 год нет.

Обычная проверка названий OWASP не даёт здесь одобрения; его даёт тест, привязанный к развёрнутому артефакту.

Для каждой найденной проблемы задайте четыре вопроса. Какая граница нарушена? Что может сделать злоумышленник? Что изменилось? Какой тест демонстрирует изменение?

JSX экранирует обычные значения; проверьте каждый escape hatch

React экранирует значения, интерполированные в обычный JSX:

<p>{displayName}</p>

Если displayName содержит разметку, React отображает её как текст. По возможности сохраняйте этот путь по умолчанию.

Выполните поиск по репозиторию для dangerouslySetInnerHTML, eval() и new Function(). Проверьте динамически собираемые значения href или src, Markdown- и HTML-рендереры, схемы URL, которые могут превратиться в javascript:, а также сторонние компоненты, принимающие необработанный HTML.

// Safe default: the user-provided name is rendered as text
<h2>{displayName}</h2>

// Unsafe unless invoice.notes has been deliberately sanitized
<div dangerouslySetInnerHTML={{ __html: invoice.notes }} />

Удалите dangerouslySetInnerHTML, если функция не требует HTML. Если приёмник остаётся, потребуйте документированную причину, политику обработки ввода и тесты выбранного sanitizer. Используйте документированный allowlist этого sanitizer, а не предполагайте, что существует единый универсально безопасный набор элементов и атрибутов.

Проверьте случаи, которые разрешает ваш рендерер. Проверьте исполняемые схемы URL, атрибуты обработчиков событий и опасные атрибуты SVG или HTML. Тестируйте отрендеренные ссылки, изображения и frames. URL data: заслуживают отдельного рассмотрения, если функция их не требует.

«Хранится в нашей базе данных» не означает «доверенное». База данных часто содержит контент, отправленный пользователями, интеграциями или импортированными файлами.

Проверяйте ссылки так же тщательно, как HTML. Управляемый пользователем URL — это данные, требующие валидации, даже когда JSX безопасно отображает окружающий элемент.

Серверная валидация и авторизация остаются обязательными. Скрытие кнопки в React меняет интерфейс. Оно не меняет того, кто может вызвать API.

Секрет, видимый клиенту, блокирует выпуск

Рассмотрим React-dashboard, в котором пользователи загружают счета провайдеру обработки документов. Соблазнительная архитектура отправляет запрос непосредственно из браузера, а значит, приватный ключ провайдера должен попасть в браузер через запрос, bundle или сгенерированную конфигурацию.

Документация по безопасности React Native формулирует правило: «Никогда не храните чувствительные API-ключи в коде приложения. Всё, что включено в ваш код, может быть доступно в виде обычного текста любому, кто исследует bundle приложения».

Если секрет находится в React bundle, выпуск блокируется. Именование .env — это техническая организация сборки, а не защита. Во многих React toolchain переменные окружения, предназначенные для клиента, встраиваются во время сборки; проверьте поведение вашего фреймворка и изучите артефакт. Переименование переменной в .env — это гигиена конфигурации, а не управление секретами.

Используйте одну конкретную границу:

  1. React-клиент загружает счет в вашу serverless function.
  2. Function аутентифицирует пользователя и проверяет авторизацию.
  3. Function авторизует запрошенный счет и tenant на сервере; никогда не полагайтесь на ID счета или скрытое состояние интерфейса.
  4. Function читает приватный ключ провайдера из серверной конфигурации.
  5. Она вызывает API обработки документов и возвращает только разрешённый результат.
React client → Blackhawk-controlled serverless function → third-party invoice API
                                                                    ↑
                                                             private API key

[IMAGE PLACEHOLDER: React client sends invoices to a Blackhawk-controlled serverless function, which alone holds the secret and calls the third-party invoice API]

Function всё ещё нужны лимиты запросов, валидация ввода, авторизация и аккуратная обработка ошибок. Вашему proxy всё ещё нужны эти средства контроля; пересылка каждого запроса каждому пользователю создаёт дорогостоящую утечку.

Перед выпуском изучите JavaScript bundle и source maps, сгенерированную публичную конфигурацию, сетевые запросы браузера и хранилище. Также проверьте ответы об ошибках и видимые клиенту hostname. Исключите production source maps или ограничьте доступ к ним в соответствии с вашей политикой отладки. В обоих случаях проверьте их на наличие учётных данных.

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

Сохраняйте безвредное состояние; не храните bearer-токены в localStorage

localStorage сохраняется после перезагрузки, что делает его удобным. Любой JavaScript, выполняющийся на странице, может прочитать хранящийся там токен; скомпрометированная зависимость — один из способов доставки такого кода.

Хранение только в памяти удаляет сохранённую копию после перезагрузки; оно не защищает активную страницу от XSS.

Сессия на основе cookie может лучше подходить, когда сервер владеет этой архитектурой. HttpOnly не позволяет JavaScript страницы напрямую читать cookie, а Secure ограничивает передачу HTTPS. Вам всё ещё нужны серверная авторизация и средства защиты от CSRF, соответствующие архитектуре cookie и запросов.

Используйте это правило принятия решения:

ДанныеРешение о выпуске
Тема, закрытые уведомления, нечувствительные настройкиСохранение обычно допустимо
Данные cacheСохраняйте только данные, которые вы готовы раскрыть тому, кто может прочитать профиль браузера; исключите учётные данные и чувствительное содержимое счетов
Access- или refresh-токеныПо умолчанию не сохраняйте; предпочитайте управляемую сервером сессию или тщательно спроектированный flow только в памяти
Содержимое счетов и чувствительные черновикиСохраняйте только после определения политики хранения и защиты
Полное дерево Redux или клиентского состоянияНе сериализуйте автоматически

Изучите конфигурацию сохранения на наличие root reducer или пути сериализованного состояния, включающего учётные данные, данные счетов или сведения о пользователях. Проверьте Sentry, Crashlytics, логи, аналитику и payload ошибок. Ищите заголовки авторизации, токены, содержимое счетов и персональную информацию.

Это руководство может сказать вам, что проверять, но оно не может сертифицировать авторизацию API или конфигурацию identity provider на основе одного фронтенда. Тестируйте эти потоки в развёрнутой системе. Скриншоты и чистый отчёт сканера — слабые свидетельства.

Для invoice-dashboard проверьте хранилище после входа, загрузите счет в production-артефакте, вызовите контролируемую ошибку и изучите telemetry-payload.

OAuth требует PKCE и проверенного состояния аутентификации

Для React-фронтенда, использующего OAuth, проверьте authorization-code flow с Proof Key for Code Exchange (PKCE).

Последовательность такова:

  1. Клиент генерирует случайный code_verifier.
  2. Он получает challenge S256, применяя SHA-256 к verifier и кодируя результат в соответствии с требованиями протокола.
  3. Он отправляет challenge вместе с authorization-запросом.
  4. Identity provider возвращает authorization code.
  5. Клиент отправляет исходный verifier во время обмена токена.
  6. Identity provider сравнивает verifier с сохранённым challenge.

Требуйте S256 и отклоняйте отсутствующие или более слабые методы code-challenge, когда ваш provider поддерживает такую политику. Украденный authorization code бесполезен без verifier.

Используйте HTTPS redirect URI и точные зарегистрированные адреса. Проверяйте state для защиты authorization flow от CSRF. Для OpenID Connect сначала проверяйте nonce. Затем проверьте подпись ID-токена, issuer и audience. Валидация OAuth authorization-code сосредоточена на клиенте, redirect URI, state и flow token endpoint; проверки OpenID Connect применяются, когда вы валидируете identity token.

Рекомендации по безопасности React Native предупреждают, что мобильные deep links небезопасны, поскольку схемы URL не имеют централизованной регистрации, и другое приложение может заявить ту же схему. Эта оговорка относится к мобильным развёртываниям. Актуальный для web контроль — PKCE: redirect передаёт ответ авторизации; ваш клиент и сервер должны проверить результирующее состояние аутентификации.

Исправьте серверную границу React и проверяйте npm как исполняемый ввод

Мы не одобряем сборку только потому, что npm audit чист. См. наш гид по защите Django-приложения перед продакшеном. Результат audit — это один сигнал; lockfile, поведение установки и граница фреймворка всё ещё требуют проверки. Зелёный badge npm audit — удобный элемент dashboard; это не решение о выпуске.

Проверьте пакеты, определяющие выполнение: react и react-dom, Next.js или другой React-фреймворк, пакеты RSC, Server Functions и связанные серверные интеграции, пакеты аутентификации и специфичные для приложения пакеты. Сравните их с текущими уведомлениями на странице безопасности React.

Волна уведомлений 2025–2026 годов включает одну критическую проблему RSC и несколько проблем отказа в обслуживании высокой степени серьёзности. Если ваше развёртывание поставляет только клиентский bundle, перечисленные уведомления RSC и Server Functions обычно не описывают этот браузерный bundle; проверьте, запускает ли ваш фреймворк затронутые серверные компоненты в продакшене.

В исследовательских заметках говорится, что две уязвимости React Sherlock в OSV от 15 августа 2026 года представлены как представление активных уязвимостей. Используйте эту цифру как отдельный сигнал, не смешивая её с историческим числом опубликованных уведомлений GitHub, которое включает исправленные проблемы.

safeguard.sh ссылается на инциденты с ua-parser-js, coa/rc и npm-червём, затронувшим 500 пакетов. Рассматривайте их как примеры проблем цепочки поставок. Превратите этот урок в средства контроля. Фиксируйте и проверяйте lockfile, затем устанавливайте зависимости из него в CI. Удаляйте неиспользуемые пакеты и изучайте install-скрипты и незнакомые добавления. Проверяйте прямые и транзитивные зависимости. Исследуйте находки высокой степени серьёзности, а не подавляйте их автоматически. Документируйте компенсирующий контроль, когда исправление невозможно внести до выпуска.

Уязвимость фреймворка и уязвимость ядра React — это отдельные классификации. Процесс выпуска должен выявлять обе.

Сложнее всего при проверке фронтенда подтвердить авторизацию на стороне провайдера; для этого вам понадобятся тесты развёрнутой системы, и никакое чистое сканирование bundle не может их заменить.

CSP ограничивает поведение браузера после доставки кода

CSP часто добавляют до устранения исходной утечки. Такой порядок создаёт успокаивающие заголовки, не исправляя раскрытие.

Снимите заголовки ответов развёрнутого приложения. Проверьте принудительное использование HTTPS, защиту от фрейминга, где это уместно, и обработку content-type. Отдельно проверьте политику source map. Создайте CSP на основе фактических источников script, connection, image, font и frame приложения. Сначала запустите её в report-only режиме, сохраните отчёт о нарушениях и зафиксируйте решение по каждому легитимному нарушению перед включением принудительного режима.

Скопированная универсальная CSP — плохой артефакт выпуска. Она может сломать легитимное развёртывание или разрешить больше, чем требуется приложению.

CSP добавляет уровень контроля на стороне браузера. Она не может удалить приватный ключ из bundle, исправить авторизацию API, санитизировать небезопасный HTML или сделать скомпрометированную зависимость надёжной. Сначала исправьте эти ошибки, затем добавьте CSP как эшелонированную защиту.

Используйте эти критерии выпуска перед продакшеном

Немедленно остановитесь, если:

  • приватные учётные данные или bearer-токен видимы клиенту;
  • high-impact HTML- или code-execution sink не имеет обоснования, политики и теста;
  • в OAuth отсутствует PKCE, когда flow его требует;
  • применимое уведомление React, RSC, Server Functions или фреймворка высокой степени серьёзности остаётся нерешённым без документированного компенсирующего контроля.

Для каждого другого пункта назначьте ответственного и потребуйте конкретные свидетельства:

  • Код: результаты поиска по репозиторию, проверка небезопасных приёмников и тесты схем URL. Включите тесты серверной авторизации.
  • Секреты и данные: проверка bundle и source map, инвентаризация хранилища, сетевой trace и тест редактирования telemetry.
  • Аутентификация: развёрнутые тесты входа, выхода, истечения срока, обновления, redirect, state и PKCE.
  • Зависимости и доставка: проверенный diff lockfile, установка из lockfile в CI, результат audit и проверка package-скриптов. Также зафиксируйте решение по уведомлению, развёрнутые заголовки, тест redirect на HTTPS, результаты CSP в report-only режиме и решение по доступу к source map.

Приложите к выпуску сканирование bundle, проверку хранилища и telemetry, тесты PKCE и аутентификации, решение по lockfile и снимок развёрнутых заголовков. Если по одному блокирующему пункту отсутствуют свидетельства, не выпускайте сборку в продакшен.