Что такое XSS уязвимость?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
XSS (Cross-Site Scripting) уязвимость
XSS — это тип атаки, при которой злоумышленник внедряет вредоносный JavaScript код в веб-приложение, который затем выполняется в браузере других пользователей. Это одна из самых распространённых веб-уязвимостей.
Как работает XSS атака
Упрощённый пример:
- Пользователь А вводит комментарий:
<img src=x onerror="alert('Hacked!')"> - Приложение сохраняет этот текст как есть в БД
- Пользователь Б видит этот комментарий на странице
- JavaScript из атрибута
onerrorвыполняется в браузере пользователя Б - Злоумышленник может украсть cookies, сессию, личные данные
Типы XSS атак
1. Reflected XSS (Отражённая)
Злоумышленник отправляет ссылку с вредоносным кодом в URL:
https://example.com/search?q=<script>alert('XSS')</script>
Приложение напрямую отражает параметр в ответе:
<!-- Небезопасно! -->
<h1>Результаты поиска: <script>alert('XSS')</script></h1>
Уязвимый код:
// React — опасно!
function SearchResults() {
const query = new URLSearchParams(window.location.search).get('q');
return <div dangerouslySetInnerHTML={{ __html: query }} />;
}
2. Stored XSS (Сохранённая)
Вредоносный код сохраняется в БД и выполняется для всех пользователей:
// Небезопасно: сохраняем пользовательский ввод как есть
function createComment(text) {
// text может быть: <img src=x onerror="stealCookies()">
db.comments.insert({ content: text });
}
// При отображении:
function Comment({ content }) {
return <div dangerouslySetInnerHTML={{ __html: content }} />;
}
3. DOM-based XSS
Уязвимость в JavaScript коде, который небезопасно работает с DOM:
// Небезопасно!
function updateProfile() {
const name = document.getElementById('name').value;
document.getElementById('greeting').innerHTML = `Hello, ${name}`;
}
// Если ввести: <img src=x onerror="alert('XSS')">
// То произойдёт выполнение скрипта
Последствия XSS атак
Злоумышленник может:
- Украсть cookies/tokens — получить доступ к аккаунту
- Перенаправить на фишинг сайт — обманом получить пароли
- Изменить содержимое страницы — распространить вредоноса или ложную информацию
- Выполнить действия от имени пользователя — создать посты, отправить сообщения
- Установить malware — перенаправить на вредоносный сайт
Как защищаться от XSS
1. Экранирование (Escaping)
Преобразуй специальные символы в HTML entities:
<!-- Небезопасно -->
<div>{{ userInput }}</div>
<!-- Безопасно в современных фреймворках -->
<div>{userInput}</div> <!-- React, Vue экранируют по умолчанию -->
Пример экранирования:
function escapeHtml(text) {
const map = {
'&': '&',
'<': '<',
'>': '>',
'"': '"',
"'": '''
};
return text.replace(/[&<>"']/g, m => map[m]);
}
const userInput = '<img src=x onerror="alert(1)">';
const safe = escapeHtml(userInput);
// Результат: <img src=x onerror="alert(1)">
// Это будет отображено как текст, не выполнится
2. Использование tekstContent вместо innerHTML
// Небезопасно
element.innerHTML = userInput; // Выполняет скрипты
// Безопасно
element.textContent = userInput; // Отображает как текст
3. React/Vue экранируют по умолчанию
// Безопасно! React экранирует
function Comment({ text }) {
return <div>{text}</div>; // Будет отображено как текст
}
// Если нужно HTML, используй дополнительный контроль
function UnsafeHTML({ html }) {
// dangerouslySetInnerHTML требует явной разметки
return <div dangerouslySetInnerHTML={{ __html: html }} />;
}
4. Content Security Policy (CSP)
HTTP заголовок, ограничивающий источники скриптов:
Content-Security-Policy: script-src 'self'
Это не позволит выполнять inline скрипты и скрипты с внешних источников.
5. Валидация ввода (Input Validation)
function validateEmail(input) {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(input);
}
// Принимаем только корректный email
if (validateEmail(userInput)) {
saveEmail(userInput);
} else {
showError('Invalid email');
}
6. Sanitization (Чистка HTML)
Для случаев, когда нужно разрешить некоторый HTML, используй библиотеки:
import DOMPurify from 'dompurify';
const userInput = '<img src=x onerror="alert(1)"><p>Safe text</p>';
const clean = DOMPurify.sanitize(userInput);
// Результат: <p>Safe text</p>
// Вредоносный код удален, безопасный HTML сохранен
Практический пример: Безопасный комментарий
import React, { useState } from 'react';
import DOMPurify from 'dompurify';
interface CommentProps {
authorName: string; // Экранируется автоматически
content: string; // Экранируется автоматически
allowedHtml?: boolean;
}
function Comment({ authorName, content, allowedHtml = false }: CommentProps) {
// Для имени автора просто экранируем
const safeName = authorName; // React сделает это
// Для содержимого с HTML
const safeContent = allowedHtml
? DOMPurify.sanitize(content)
: content; // React экранирует
return (
<div className="comment">
<strong>{safeName}</strong>
{allowedHtml ? (
<div dangerouslySetInnerHTML={{ __html: safeContent }} />
) : (
<p>{safeContent}</p>
)}
</div>
);
}
export default Comment;
Чеклист безопасности
- Никогда не используй
innerHTMLс пользовательским вводом - Экранируй весь пользовательский ввод
- Используй
textContentвместоinnerHTML - Применяй Content Security Policy
- Валидируй ввод на сервере
- Используй HTTPS для передачи данных
- Регулярно обновляй зависимости (в них могут быть уязвимости)
- Тестируй приложение на XSS уязвимости
XSS — критическая уязвимость, поэтому защита от неё должна быть приоритетом при разработке веб-приложений.