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-сутності (наприклад, <, >). Це запобігає їх сприйняттю як 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, безпека контейнерів), залиште ваші контактні дані у формі нижче.







