React разработан с механизмами предупреждения межсайтового скриптинга (XSS). Однако, как и любой фронтенд-фреймворк, он все еще может быть уязвим, если его использовать неправильно. Понимание встроенных методов защиты React и сценариев, в которых они могут выйти из строя, важно для безопасности веб-сайтов.
Понимание XSS и его влияния на веб-приложения
Что такое межсайтовый скриптинг (XSS)?
XSS – это уязвимость, позволяющая злоумышленникам внедрять вредоносные скрипты на веб-страницы, просматриваемые другими пользователями. Эти скрипты работают в браузере цели и могут красть конфиденциальные данные, выдавать себя за пользователей или манипулировать поведением веб-сайтов. Она остается одной из самых распространенных уязвимостей в веб-приложениях, часто появляясь в OWASP Top 10.
Типы XSS
- Отраженные XSS возникают, когда вредоносные входящие данные отправляются в браузер и появляются в ответе HTTP, например, через параметры URL-адреса.
- Сохраненные XSS включают поиск вредоносных скриптов в бэкенде (например, в базе данных), которые позже отображаются пользователям через обычную работу вебсайта.
- XSS на основе DOM используют уязвимости в скриптах на стороне клиента, которые динамически изменяют DOM на основе входных пользовательских данных без очистки.
Как React помогает предотвращать XSS
Фреймворк React (сначала React.js) был одним из первых, созданных с учетом безопасности, и включает функции, усложняющие внедрение XSS.
Одним из основных новшеств React является JSX – расширение синтаксиса, позволяющее разработчикам писать элементы, подобные HTML, непосредственно в JavaScript. JSX компилируется в JavaScript и воспроизводится с помощью виртуального DOM React, что добавляет уровень абстракции и безопасности при взаимодействии с DOM.
Автоматическое экранирование в JSX
React помогает защититься от XSS, главным образом экранируя отображаемые в JSX значения перед тем, как вставить их в DOM.
Как React безопасно воспроизводит HTML
По умолчанию React экранирует все значения, встроенные в выражения JSX, прежде чем отобразить их в DOM. Это делается с помощью механизма, который гарантирует, что входные данные обрабатываются как обычный текст, а не интерпретируются как исполняемый HTML или JavaScript. Это значительно снижает вероятность XSS.
Какие символы экранируются и почему
Такие символы, как <, >, &, ‘ и “, экранируются в соответствующие HTML-сущности (например, <, >).
Виртуальный DOM и безопасный рендеринг
Виртуальный DOM React добавляет еще один уровень защиты, контролируя, как обновления применяются к реальному DOM. Вместо непосредственного манипулирования DOM на основе строк или шаблонов, React создает виртуальную репрезентацию, которая дифференцируется и очищается перед внесением обновлений. Это минимизирует риск неожиданного исполнения скриптов.
Обработка динамического контента в React
Динамический контент из входящих данных пользователя или API можно безопасно отображать с помощью JSX, поскольку React экранирует его по умолчанию.
Однако если разработчики обходят эти механизмы, например, вводя HTML вручную, риски XSS снова появляются. Безопасный рендеринг требует избежания необработанного HTML и полагания на надежные библиотеки очистки, когда это необходимо.
Что может сделать вебсайты на React уязвимыми к XSS?
Несмотря на методы защиты, React не застрахован от уязвимостей XSS. Разработчики все еще могут создавать риск из-за определенных API или неправильного использования функций, обходящих обычные механизмы безопасности.
Сам JSX безопасен при правильном использовании, но он не является «песочницей» – он будет воспроизводить все, что ему поручено, что все еще делает безопасные практики написания кода важными.
Использование dangerouslySetInnerHTML
Один из самых распространенных способов повторного внедрения XSS в веб-сайт на React – это использование dangerouslySetInnerHTML, который обходит встроенное экранирование React.
Почему он существует
Атрибут dangerouslySetInnerHTML существует для поддержки сценариев, когда нужно демонстрировать необработанный HTML, например, отображение контента из CMS или HTML-форматированного Markdown. Его использование явно обозначено как «опасное», чтобы предотвратить неправильное использование и сделать акцент на рисках безопасности.
Как им можно злоупотреблять
Если разработчики используют dangerouslySetInnerHTML для отображения контента, содержащего входящие пользовательские данные или ненадежные данные, злоумышленники могут внедрять скрипты, которые будут выполняться в браузере пользователей. Это полностью обходит механизмы экранирования React и создает прямой путь для XSS.
Неправильное использование eval(), innerHTML или document.write()
Функции, такие как eval(), или свойства, такие как innerHTML, по своей сути опасны, поскольку они могут выполнять произвольный JavaScript. Их использование на ненадежных данных создает XSS-уязвимости, поскольку любой переданный вредоносный скрипт будет выполняться с привилегиями в контексте страницы.
Предоставление веб-приложений на React доступ к ненадежным сторонним скриптам
Загрузка внешних скриптов в веб-сайт на React без проверки целостности или песочницы создает риски. Они могут быть скомпрометированы или приносить вред, потенциально получая доступ к конфиденциальным данным или манипулируя состоянием сайта.
Проблемы маршрутизации на стороне клиента с неэкранированными входными данными
Библиотеки маршрутизации на стороне клиента часто используют динамические сегменты из URL для отображения контента. Если эти сегменты непосредственно вводятся в DOM без экранирования или санитарной обработки, злоумышленники могут использовать их для выполнения скриптов через XSS на основе DOM.
Реальные примеры XSS в веб-приложениях на React
Пример 1: Использование неочищенного Markdown
Рассмотрим компонент, воспроизводящий Markdown с помощью парсера, выводящего необработанный HTML. Если этот вывод осуществляется с dangerouslySetInnerHTML без санитарной обработки, злоумышленники могут использовать его.
function MarkdownViewer({ content }) {
return (
<div dangerouslySetInnerHTML={{ __html: marked(content) }} />
);
}
// Malicious input: `')"`
Без очистки content этот подход может позволить инъекцию тегов <img> с обработчиками onerror, выполняющими JavaScript.
Пример 2: Использование внешних данных через API
Предположим, что веб-приложение получает новости из внешнего API и отображает их с помощью необработанного HTML.
useEffect(() => {
fetch('/api/news')
.then(res => res.text())
.then(html => setContent(html));
}, []);
return <div dangerouslySetInnerHTML={{ __html: content }} />;
Если API скомпрометировано или данные не фильтруются должным образом, злоумышленники могут внедрять скрипты через возвращенный HTML-код, подвергая пользователей риску XSS.
Пример 3: Неправильно настроенный dangerouslySetInnerHTML
Даже с хорошими намерениями, неправильно настроенное использование dangerouslySetInnerHTML может привести к XSS.
const SafeHtml = ({ rawHtml }) => (
<div dangerouslySetInnerHTML={{ __html: rawHtml }} />
);
// rawHtml might contain: `<script>alert('XSS')</script>`
Если rawHtml не будет очищен перед передачей, это приведет к выполнению произвольных скриптов, встроенных во входные данные.
Лучшие практики предотвращения XSS в React
Не использовать dangerouslySetInnerHTML, если это не является абсолютно необходимым
При отображении необработанного HTML следует очистить содержимое с помощью надежной библиотеки и проверить источник данных.
Проверенные библиотеки для очистки HTML
Библиотеки, такие как DOMPurify специально разработаны для очистки HTML и удаления потенциально опасных элементов и атрибутов. Их следует всегда применять перед использованием HTML в DOM.
Проверка и очистка входных данных в бэкенде
Проверка на стороне сервера позволяет убедиться, что вредоносные данные не попадут в систему, дополняя защиту на стороне клиента.
Избегание встроенного JavaScript и встроенных обработчиков событий
Следует придерживаться привязки событий (event binding) JSX и избегать создания обработчиков на основе входных пользовательских данных, что может привести к инъекции кода.
Суровая политика безопасности контента (CSP)
Надежная CSP может блокировать выполнение скриптов из неавторизованных источников и добавлять критический уровень защиты. Она особенно полезна как резервный вариант, когда другие средства защиты не работают.
Например, установка Content-Security-Policy: default-src ‘self’ ограничивает скрипты теми, которые размещены на конкретном домене.
Использование заголовков безопасности
Как и в любом другом приложении, вебсайт на основе React должен использовать заголовки безопасности, чтобы минимизировать риск не только XSS, но и многих других классов атак.
HTTPOnly и безопасные cookie
Следует отмечать аутентификационные cookie как HttpOnly, чтобы предотвратить доступ с JavaScript и как Secure, обеспечить их передачу только через HTTPS. Это защищает данные сессии, даже если другие части веб-сайта скомпрометированы.
Заголовки Referrer-Policy и X-XSS-Protection
Следует применять Referrer-Policy, чтобы ограничить конфиденциальные данные рефереров (referrer) в запросах. Хотя X-XSS-Protection устарел, он все еще может предлагать ограниченную защиту в более старых браузерах.
Методы тестирования веб-сайтов на React на наличие XSS
Статический анализ кода
SAST, например в Mend.io, может обнаруживать распространенные проблемы написания кода, включая опасное использование API. Его можно внедрить на ранних этапах разработки и просканировать всю базу кода, давая возможность удостовериться в безопасности даже в начале проекта.
Однако статическому анализу не хватает контекста выполнения программы, поэтому он пропускает связанные с этим уязвимости.
Динамическое тестирование (например, с помощью сканеров уязвимостей)
Инструменты динамического тестирования безопасности приложений (DAST), такие, как Invicti (на основе Netsparker и Acunetix), взаимодействуют с запущенными приложениями для обнаружения реальных, пригодных для использования XSS-уязвимостей.
Также подтверждение уязвимостей в Invicti помогает командам сосредоточиться на исправлении настоящих проблем безопасности, минимизируя повторные проверки.
Лучшая практика: комбинация методов
Чтобы убедиться в безопасности кода с ранних этапов разработки, иметь возможность просканировать весь свой код и выявлять все доступные уязвимости при выполнении веб-сайта, важно комбинировать методы DAST и SAST.
Таким образом, команда может комплексно подойти к вопросу тестирования безопасности, не упуская важные моменты.
Чтобы бесплатно протестировать инструменты Invicti (DAST) и Mend.io (SAST, SCA, безопасность контейнеров), оставьте свои контактные данные в форме ниже.







