Открыть сервис

Хранимый XSS

Хранимый XSS (также известный как постоянный или Stored XSS) — это тип межсайтового скриптинга (XSS), при котором вредоносный код (скрипт) постоянно сохраняется на сервере веб-приложения (например, в базе данных, на файловой системе, в логах) и затем выполняется в браузере пользователя при каждом обращении к уязвимой странице. В отличие от отражённого XSS (Reflected XSS), хранимый XSS не требует отправки специально сформированной ссылки жертве, так как код автоматически загружается и исполняется при просмотре легитимного контента.

Механизм атаки

Атака с использованием хранимого XSS включает несколько этапов:

  1. Внедрение вредоносного кода. Злоумышленник находит на веб-сайте форму ввода данных, которая не фильтрует или не экранирует пользовательский ввод (например, поле для комментариев, имя пользователя, сообщение на форуме, отзыв о товаре). В это поле он вводит строку, содержащую HTML-теги и JavaScript-код, например: <script>alert('XSS')</script>.
  2. Сохранение на сервере. Сервер принимает ввод и сохраняет его в базу данных или другое хранилище без надлежащей санитизации (очистки от опасных символов).
  3. Загрузка страницы жертвой. Когда другой пользователь (или сам злоумышленник) открывает страницу, на которой отображается сохранённый контент (например, страницу с комментариями), сервер извлекает данные из хранилища и вставляет их в HTML-код страницы.
  4. Исполнение скрипта. Браузер жертвы интерпретирует вставленный код как часть HTML-документа и выполняет вредоносный JavaScript-скрипт в контексте безопасности этого сайта.

Отличия от других типов XSS

Хранимый XSS отличается от других основных типов межсайтового скриптинга:

  • Отражённый XSS (Reflected XSS). Вредоносный код не сохраняется на сервере, а передаётся в запросе (например, в URL-параметре) и сразу же отражается в ответе сервера. Для атаки требуется, чтобы жертва перешла по специально сформированной ссылке.
  • DOM-based XSS. Уязвимость возникает на стороне клиента, когда JavaScript-код страницы динамически изменяет DOM-дерево, используя данные из ненадёжного источника (например, document.location.hash или window.name), без сохранения на сервере.

Ключевое отличие хранимого XSS — его постоянство и способность поражать всех пользователей, посещающих уязвимую страницу, без необходимости активных действий с их стороны (например, клика по ссылке).

Примеры уязвимых мест

Хранимый XSS часто встречается в следующих функциональных возможностях веб-приложений:

  • Комментарии и форумы. Поля для ввода текста сообщений, имени пользователя, темы.
  • Профили пользователей. Поля «О себе», «Имя», «Город», «Сайт».
  • Блоги и CMS. Поля для заголовков, содержимого статей, мета-тегов.
  • Системы отзывов и рейтингов. Поля для текста отзыва.
  • Чат-системы и мессенджеры. Сообщения, которые отображаются в истории чата.
  • Логи и системы мониторинга. Если данные логов выводятся на веб-страницу без экранирования.

Потенциальный ущерб

Последствия успешной атаки хранимого XSS могут быть серьёзными:

  • Кража сессионных cookie. Скрипт может отправить cookie жертвы на сервер злоумышленника, что позволяет угнать сессию и получить доступ к учётной записи жертвы.
  • Перенаправление на фишинговые сайты. Пользователь может быть перенаправлен на поддельную страницу входа, где у него будут украдены логин и пароль.
  • Дефейс (изменение внешнего вида) сайта. Скрипт может изменить содержимое страницы, отображая произвольный текст, изображения или ссылки.
  • Загрузка вредоносного ПО. Пользователь может быть принуждён к загрузке и запуску вредоносного файла.
  • Выполнение произвольных действий от имени пользователя. Скрипт может отправлять запросы от имени жертвы (например, публиковать комментарии, переводить деньги, менять настройки), используя её сессию.
  • Распространение червя. Вредоносный скрипт может самовоспроизводиться, создавая новые комментарии или сообщения, содержащие тот же скрипт, что приводит к массовому заражению.

Методы защиты

Защита от хранимого XSS основывается на принципе «никогда не доверяй пользовательскому вводу». Основные методы:

Валидация и санитизация ввода

  • Валидация на стороне сервера. Проверка вводимых данных на соответствие ожидаемому формату (например, для поля «Возраст» — только цифры, для поля «Имя» — только буквы и пробелы). Всё, что не соответствует формату, должно отвергаться.
  • Санитизация (очистка) ввода. Удаление или экранирование опасных символов и HTML-тегов. Для этого используются специализированные библиотеки, такие как HTML Purifier (PHP) или OWASP Java HTML Sanitizer. Рекомендуется удалять все HTML-теги, кроме безопасного разрешённого набора (например, для форматирования текста в комментариях).

Экранирование вывода

  • Контекстно-зависимое экранирование. При вставке данных в HTML-код страницы необходимо экранировать их в зависимости от контекста (HTML-тело, атрибут тега, JavaScript-строка, CSS-значение). Для этого используются шаблонизаторы (например, Twig, Jinja2, React JSX) с автоматическим экранированием.
  • Использование Content Security Policy (CSP). HTTP-заголовок Content-Security-Policy позволяет ограничить источники, из которых браузер может загружать и выполнять скрипты. Например, директива script-src 'self' запретит выполнение любых инлайн-скриптов, включая внедрённые через XSS.

Прочие меры

  • HTTPOnly cookie. Установка флага HttpOnly для сессионных cookie запрещает доступ к ним из JavaScript-кода, что предотвращает их кражу через XSS.
  • Регулярные аудиты безопасности. Использование автоматических сканеров уязвимостей (например, OWASP ZAP, Burp Suite) и ручное тестирование на проникновение.
  • Обучение разработчиков. Понимание принципов безопасного кодирования и типов XSS-атак.

Пример уязвимого и защищённого кода

Уязвимый код (PHP)

```php <?php // Сохранение комментария $comment = $_POST['comment']; // Вставка в БД без фильтрации $db->query("INSERT INTO comments (text) VALUES ('$comment')");

// Вывод комментария $result = $db->query("SELECT text FROM comments"); while ($row = $result->fetch_assoc()) { echo "<p>" . $row['text'] . "</p>"; // Опасный вывод без экранирования } ?> ```

Защищённый код (PHP)

```php <?php // Сохранение комментария с санитизацией $comment = htmlspecialchars($_POST['comment'], ENT_QUOTES, 'UTF-8'); // Вставка в БД с использованием подготовленных выражений $stmt = $db->prepare("INSERT INTO comments (text) VALUES (?)"); $stmt->bind_param("s", $comment); $stmt->execute();

// Вывод комментария $result = $db->query("SELECT text FROM comments"); while ($row = $result->fetch_assoc()) { echo "<p>" . htmlspecialchars($row['text'], ENT_QUOTES, 'UTF-8') . "</p>"; // Безопасный вывод } ?> ```

Источники

  1. OWASP (Open Web Application Security Project). "Cross-Site Scripting (XSS)". OWASP Foundation.
  2. OWASP. "DOM based XSS Prevention Cheat Sheet". OWASP Foundation.
  3. OWASP. "XSS Filter Evasion Cheat Sheet". OWASP Foundation.
  4. PortSwigger Web Security Academy. "Cross-site scripting (XSS)". PortSwigger Ltd.
  5. Acunetix. "Stored XSS (Persistent XSS)". Acunetix.
  6. MDN Web Docs. "Content Security Policy (CSP)". Mozilla Corporation.

BFOmetr — база данных и аналитика по компаниям России.

На главную BFOmetr →