Как React защищает от XSS?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Как React защищает от XSS?
XSS (Cross-Site Scripting) — это атака, когда вредоносный код (обычно JavaScript) внедряется на веб-сайт и выполняется в браузере пользователя. React имеет встроенные механизмы защиты от этого.
Что такое XSS?
// Пример уязвимости
const userInput = '<img src=x onerror="alert(\"Hacked!\")">'; // Опасные данные от пользователя
// В обычном HTML/jQuery
document.innerHTML = userInput; // Выполнит JavaScript!
// Результат: попап "Hacked!" - атака сработала
Как React защищает
1. Экранирование (Escaping) - главная защита
React по умолчанию экранирует все текстовые данные в JSX:
const userInput = '<img src=x onerror="alert(\"Hacked!\")">'; // XSS попытка
function Component() {
return <div>{userInput}</div>; // Безопасно!
}
// React отобразит буквальный текст:
// <div><img src=x onerror="alert(\"Hacked!\")"></div>
// XSS не выполнится!
Как работает экранирование:
Опасные символы -> Экранированы
< -> <
> -> >
" -> "
' -> '
& -> &
Браузер отображает экранированный текст как обычный текст, а не как HTML.
2. JSX преобразует в функции
JSX не выполняет произвольный код, а преобразует в функции React:
// JSX
<div className="hello">{message}</div>
// После преобразования
React.createElement('div', { className: 'hello' }, message);
// React проверяет типы и экранирует
3. Специальные атрибуты требуют осторожности
Данные в атрибутах требуют осторожности. React проверяет некоторые из них:
const userInput = 'javascript:alert("XSS")';
// ❌ Опасно
<a href={userInput}>Link</a>
// ✅ React блокирует javascript: протоколы
// Вывод: href="" (атрибут игнорируется)
// Протоколы, которые React блокирует:
// javascript:
// data: (в некоторых контекстах)
// vbscript:
Уязвимые паттерны (когда React НЕ защищает)
1. dangerouslySetInnerHTML
Этот метод специально создан для вставки HTML, поэтому ответственность на тебе:
// ❌ ОЧЕНЬ ОПАСНО!
const userInput = '<img src=x onerror="alert(\"Hacked!\")">'; // От пользователя
function Component() {
return (
<div
dangerouslySetInnerHTML={{ __html: userInput }}
/>
);
}
// XSS сработает!
// ✅ Только для доверенного контента
const trustedHTML = '<b>Bold text</b>'; // Ты сам написал
function Component() {
return <div dangerouslySetInnerHTML={{ __html: trustedHTML }} />;
}
Когда использовать dangerouslySetInnerHTML:
- Очень редко
- Только для контента, которому ты доверяешь
- Всегда санитизируй входные данные (используй библиотеки)
import DOMPurify from 'dompurify';
const userInput = '<img src=x onerror="alert(\"Hacked!\")">'; // Опасные данные
function Component() {
const cleanHTML = DOMPurify.sanitize(userInput); // Очищаем
return <div dangerouslySetInnerHTML={{ __html: cleanHTML }} />;
}
// DOMPurify удалит опасный onerror обработчик
// Результат: <img src="x">
2. Атрибуты event handlers
Опасно интерполировать строки в обработчики событий:
// ❌ Неправильно
const handler = userInput; // Может содержать код
return <button onClick={handler}>Click</button>; // Опасно!
// ✅ Правильно
const handleClick = () => {
// Твой код
};
return <button onClick={handleClick}>Click</button>;
3. Динамические style
Опасно вставлять пользовательские стили:
// ❌ Опасно (хотя обычно безопасно из-за CSS синтаксиса)
const style = userInput; // expression: alert(1)
return <div style={style}>Content</div>;
// ✅ Правильно
const style = { color: 'red', fontSize: '14px' };
return <div style={style}>Content</div>;
Практические примеры защиты
Пример 1: Комментарии пользователей
import DOMPurify from 'dompurify';
function CommentList({ comments }) {
return (
<ul>
{comments.map(comment => (
<li key={comment.id}>
<strong>{comment.author}</strong>
{/* Безопасно - React экранирует */}
<p>{comment.text}</p>
</li>
))}
</ul>
);
}
// Если нужен HTML (форматирование):
function FormattedCommentList({ comments }) {
return (
<ul>
{comments.map(comment => (
<li key={comment.id}>
<strong>{comment.author}</strong>
{/* Санитизируем перед вставкой */}
<div
dangerouslySetInnerHTML={{
__html: DOMPurify.sanitize(comment.htmlContent)
}}
/>
</li>
))}
</ul>
);
}
Пример 2: Ссылки
function LinkComponent({ url, label }) {
// React блокирует javascript: протоколы
return <a href={url}>{label}</a>;
}
// Использование
<LinkComponent
url="javascript:alert('XSS')" // Безопасно - React проигнорирует
label="Click"
/>
// Дополнительная проверка (рекомендуется)
function SafeLink({ url, label }) {
// Проверяем протокол
const isValidUrl = url && (url.startsWith('/') || url.startsWith('http'));
return (
<a href={isValidUrl ? url : '#'}>
{label}
</a>
);
}
Пример 3: Поиск (динамический контент)
function SearchResults({ query, results }) {
return (
<div>
{/* Безопасно - React экранирует query */}
<p>Результаты для: <strong>{query}</strong></p>
<ul>
{results.map(result => (
<li key={result.id}>
{/* Безопасно */}
<a href={result.url}>{result.title}</a>
<p>{result.description}</p>
</li>
))}
</ul>
</div>
);
}
// Даже если query = "<script>alert('XSS')</script>"
// React отобразит литерально текст, не выполнит скрипт
Инструменты для дополнительной защиты
// 1. DOMPurify - удаляет опасный HTML
import DOMPurify from 'dompurify';
const clean = DOMPurify.sanitize(userInput);
// 2. Markdown с ограничениями
import { marked } from 'marked';
const html = marked(userInput, { breaks: true });
const clean = DOMPurify.sanitize(html);
// 3. Валидация URL
function isValidUrl(url) {
try {
const parsed = new URL(url);
return ['http:', 'https:', 'mailto:', '/'].includes(parsed.protocol);
} catch {
return false;
}
}
// 4. Content Security Policy (CSP)
// В HTML head
<meta
http-equiv="Content-Security-Policy"
content="default-src 'self'; script-src 'self' 'unsafe-inline'"
/>
Checklist безопасности для Frontend Developer
- ✅ React автоматически экранирует текст в JSX
- ❌ Не используй dangerouslySetInnerHTML без санитизации
- ✅ React блокирует javascript: протоколы в href
- ❌ Не доверяй данным от пользователей
- ✅ Используй библиотеки вроде DOMPurify для HTML
- ✅ Устанавливай Content-Security-Policy заголовки
- ❌ Не вставляй пользовательский код в onclick и другие обработчики
- ✅ Валидируй все входные данные
Выводы
React защищает от XSS по умолчанию через:
- Экранирование текста в JSX
- Преобразование JSX в функции (не в строки)
- Блокирование опасных протоколов (javascript:)
- Требование явного использования dangerouslySetInnerHTML
Твоя ответственность:
- Никогда не используй dangerouslySetInnerHTML без санитизации
- Валидируй пользовательский ввод
- Используй санитизирующие библиотеки для HTML контента
- Следи за Content-Security-Policy
React — это безопасный по умолчанию фреймворк, но ты должен понимать ограничения и использовать дополнительные инструменты где нужно.