Это тип уязвимости веб-приложений, при которой злоумышленник внедряет вредоносный код в страницу сайта, сервера или базу данных, а браузер другого пользователя исполняет его как доверенный.
Обновлено: 9 июля 2026
Это тип уязвимости веб-приложений, при которой злоумышленник внедряет вредоносный код в страницу сайта, сервера или базу данных, а браузер другого пользователя исполняет его как доверенный.
Главная опасность XSS в том, что атака направлена не на сервер напрямую, а на пользователей сайта. Браузер жертвы не знает, что скрипт вредоносный: он получает его от доверенного ресурса и исполняет.
XSS входит в список критичных уязвимостей по версии OWASP Top 10 и встречается как на небольших сайтах, так и в крупных веб-приложениях с миллионами пользователей.
XSS — это сокращение от Cross-Site Scripting, что дословно переводится как «межсайтовый скриптинг». Сокращение используется именно в виде XSS, а не CSS — чтобы не путать с CSS (Cascading Style Sheets), языком стилей веб-страниц.
Термин появился в конце 1990-х годов, когда исследователи безопасности начали описывать атаки, при которых скрипты одного сайта исполнялись в контексте другого. Со временем значение термина расширилось: сегодня под XSS понимают любое внедрение и выполнение вредоносного кода в веб-интерфейсе через незащищенный ввод или вывод данных.
Представьте интернет-магазин с разделом отзывов. Покупатели оставляют комментарии о товарах, и сайт отображает их на странице продукта.
Злоумышленник оставляет необычный текст, а сообщение со вставленным скриптом. Если сайт не проверяет и не обрабатывает пользовательский ввод перед выводом, вредоносный код сохраняется в базе данных и попадает на страницу.
Когда следующий покупатель открывает страницу товара, его браузер загружает страницу вместе со скриптом. Браузер не знает, что скрипт вредоносный: он получен от доверенного сайта магазина. Вредоносный скрипт исполняется и данные утекли злоумышленнику. Именно так работает базовая XSS-атака, через доверие браузера к содержимому страницы.
В основе XSS лежит простая идея: если сайт принимает данные от пользователя и выводит их обратно на страницу без должной обработки, злоумышленник может подменить эти данные вредоносным кодом. Браузер получит страницу с этим кодом и исполнит его в привилегированном контексте сайта.
Проблема не в самом JavaScript как языке. Проблема — в том, как приложение обращается с пользовательскими данными: принимает, хранит, обрабатывает и выводит их.
Точкой входа для XSS служит любое место, где сайт принимает данные от пользователя и впоследствии отображает их.
Типичные векторы внедрения:
Браузер работает по простому принципу, если контент получен от сайта, которому пользователь доверяет, браузер исполняет его без дополнительных вопросов. Он не умеет отличать "авторский" JavaScript от кода, который злоумышленник внедрил через уязвимое поле ввода.
Хорошая метафора: представьте официальное письмо от банка. Вы доверяете отправителю и читаете содержимое. Но если злоумышленник смог вложить в конверт свою записку вместе с оригинальным письмом, вы прочитаете и её — потому что доверяете источнику, а не содержимому.
Именно так работает XSS, браузер доверяет сайту и исполняет весь код, который получает от него, включая внедренный злоумышленником.
Короткий ответ: страдают все.
Технически скрипт исполняется в браузере пользователя. Но последствия затрагивают каждую из сторон
| Сторона | Что происходит | Последствия |
| Пользователь | Скрипт исполняется в его браузере | Кража данных, компрометация аккаунта, фишинг |
| Сайт | Используется как вектор атаки | Потеря доверия, технические инциденты |
| Бизнес | Репутационный и финансовый ущерб | Потеря клиентов, затраты на реагирование, юридические риски |
Владелец сайта несет ответственность за то, что происходит с данными пользователей на его платформе. Даже если атака технически реализована через браузер клиента, источником проблемы является небезопасный код приложения.
Все XSS-уязвимости объединяет одна механика: вредоносный скрипт попадает на страницу и исполняется браузером. Но способ доставки и хранения вредоносного кода различается. Именно по этому признаку принято выделять три основных типа XSS.
| Тип | Payload хранится | Жертва | Масштаб угрозы |
| Stored XSS | На сервере / в БД | Все посетители страницы | Высокий |
| Reflected XSS | Нигде, отражается в ответе | Конкретный пользователь | Средний |
| DOM-based XSS | Только в клиентском коде | Конкретный пользователь | Средний / высокий |
Stored XSS (также называют Persistent XSS или постоянная XSS) — это вид атаки, при котором вредоносный скрипт сохраняется на сервере или в базе данных и затем отображается другим пользователям.
Почему это особенно опасно: Один payload может затронуть неограниченное число пользователей. Злоумышленнику не нужно взаимодействовать с каждой жертвой отдельно.
Где чаще всего встречается:
Пример сценария: злоумышленник оставляет отзыв на товар со скриптом. Тысячи покупателей, открывающих страницу товара, получают исполненный вредоносный код в своем браузере.
Reflected XSS (отраженная XSS) — это тип атаки, при котором вредоносный payload не сохраняется на сервере, а сразу "отражается" в HTTP-запросе и попадает на страницу.
Как это работает:
Ключевая особенность: Reflected XSS требует, чтобы жертва сама перешла по подготовленной ссылке. Именно поэтому эта атака часто сочетается с социальной инженерией: злоумышленник маскирует ссылку под легитимную и отправляет ее жертве.
Где чаще всего встречается:
Пример сценария: злоумышленник отправляет пользователю ссылку на знакомый сайт с вредоносным параметром в URL. Пользователь доверяет домену и переходит. Страница загружается как обычно, но вместе с ней исполняется скрипт.
XSS — это не абстрактный технический баг. Это реальный вектор атаки с измеримыми последствиями для пользователей и бизнеса. Выполненный скрипт может читать данные страницы, отправлять их злоумышленнику, выполнять действия от имени пользователя и полностью подменять интерфейс.
Что может сделать злоумышленник через XSS:
Один из наиболее известных сценариев эксплуатации XSS — получение доступа к сессионным данным пользователя.
Как это происходит: Исполненный скрипт может читать данные, доступные в контексте страницы: токены, идентификаторы сессий, данные форм, информацию из localStorage и sessionStorage. Эти данные отправляются злоумышленнику, который получает возможность действовать от имени жертвы.
Что оказывается под угрозой:
Важно: атрибут HttpOnly для cookie закрывает доступ к ним через JavaScript, что снижает часть рисков. Но XSS не ограничивается только кражей cookie. Злоумышленник может читать данные страницы, перехватывать ввод форм и выполнять действия от имени пользователя даже без доступа к cookie.
XSS позволяет злоумышленнику изменить то, что видит пользователь на странице сайта: подменить форму входа, добавить фальшивое уведомление, встроить поддельную кнопку оплаты или полностью заменить интерфейс.
Чем это опаснее обычного фишинга? Классический фишинг использует поддельный домен, который внимательный пользователь может распознать. При XSS подмена происходит на реальном домене, которому пользователь доверяет. Адресная строка браузера показывает знакомый URL — это усыпляет бдительность.
Типичные сценарии подмены:
| Что подменяется | Цель злоумышленника |
| Форма входа | Кража логина и пароля |
| Форма оплаты | Перехват платежных данных |
| Уведомление или баннер | Социальная инженерия |
| Кнопка действия | Выполнение нежелательного действия |
| Контент страницы | Дезинформация, манипуляция |
| Редирект | Перенаправление на вредоносный ресурс |
Пример сценария: злоумышленник через XSS подменяет форму входа в личный кабинет интернет-магазина. Пользователь видит привычный интерфейс на знакомом домене, вводит логин и пароль — данные уходят злоумышленнику, а не на сервер магазина.
XSS позволяет злоумышленнику изменить то, что видит пользователь на странице сайта: подменить форму входа, добавить фальшивое уведомление, встроить поддельную кнопку оплаты или полностью заменить интерфейс.
Чем это опаснее обычного фишинга? Классический фишинг использует поддельный домен, который внимательный пользователь может распознать. При XSS подмена происходит на реальном домене, которому пользователь доверяет. Адресная строка браузера показывает знакомый URL — это усыпляет бдительность.
Типичные сценарии подмены:
| Что подменяется | Цель злоумышленника |
| Форма входа | Кража логина и пароля |
| Форма оплаты | Перехват платежных данных |
| Уведомление или баннер | Социальная инженерия |
| Кнопка действия | Выполнение нежелательного действия |
| Контент страницы | Дезинформация, манипуляция |
| Редирект | Перенаправление на вредоносный ресурс |
Пример сценария: злоумышленник через XSS подменяет форму входа в личный кабинет интернет-магазина. Пользователь видит привычный интерфейс на знакомом домене, вводит логин и пароль — данные уходят злоумышленнику, а не на сервер магазина.
XSS — не привилегия устаревших или плохо сделанных сайтов. Уязвимость возникает там, где пользовательские данные принимаются, обрабатываются и выводятся обратно — а это есть практически в каждом современном веб-приложении. Разница лишь в том, насколько безопасно реализована эта цепочка.
Любой интерфейсный элемент, который принимает ввод от пользователя и затем отображает его, является потенциальной точкой риска.
Типичные зоны риска:
XSS — не привилегия устаревших или плохо сделанных сайтов. Уязвимость возникает там, где пользовательские данные принимаются, обрабатываются и выводятся обратно — а это есть практически в каждом современном веб-приложении. Разница лишь в том, насколько безопасно реализована эта цепочка.
Любой интерфейсный элемент, который принимает ввод от пользователя и затем отображает его, является потенциальной точкой риска.
Типичные зоны риска:
Современные frontend-приложения на React, Vue, Angular и других фреймворках не защищены от XSS автоматически. Фреймворки предоставляют встроенные механизмы защиты, но они работают только при правильном использовании. Небезопасные практики разработки открывают путь к DOM-based XSS даже в современных приложениях.
Типичные ошибки в SPA-приложениях:
| Характеристика | Классический сайт | SPA-приложение |
| Где формируется HTML | На сервере | В браузере |
| Видимость payload серверу | Высокая | Низкая |
| Встроенная защита | Зависит от бэкенда | Зависит от фреймворка |
| Основной риск | Stored / Reflected XSS | DOM-based XSS |
| Сложность обнаружения | Средняя | Высокая |
Важно для команд разработки: использование React, Vue или Angular не означает автоматическую защиту от XSS. Фреймворк защищает только при соблюдении безопасных практик работы с данными.
Чтобы лучше понять механику XSS, полезно рассмотреть конкретный сценарий. Ниже — упрощенный образовательный пример, который показывает логику атаки без рабочих эксплойтов.
Исходная ситуация: Интернет-магазин позволяет покупателям оставлять отзывы о товарах. Отзывы сохраняются в базе данных и отображаются на странице товара для всех посетителей.
Он проверяет, как сайт обрабатывает пользовательский ввод. Поле отзыва принимает произвольный текст и выводит его на страницу без обработки.
Вместо обычного текста он вводит фрагмент, содержащий скрипт. Сайт принимает его как обычный отзыв и сохраняет в базе данных.
Любой посетитель, открывающий страницу товара, получает HTML с сохраненным скриптом.
Браузер посетителя не различает авторский код сайта и внедренный скрипт. Он исполняет всё, что получил в составе страницы.
Скрипт выполняет заложенную злоумышленником логику: читает данные, отправляет их на внешний сервер, подменяет интерфейс или выполняет действия от имени пользователя.
После того как скрипт исполнен в браузере жертвы, злоумышленник получает возможность реализовать широкий спектр сценариев — в зависимости от того, какую логику он заложил в payload.
Возможные действия после исполнения скрипта:
Насколько быстро это происходит? Исполнение скрипта и передача данных злоумышленнику занимают доли секунды. Пользователь чаще всего не замечает ничего подозрительного: страница выглядит и работает как обычно.
Для бизнеса это означает: факт компрометации может долгое время оставаться незамеченным — особенно при Stored XSS, когда payload активен на странице до момента его обнаружения и удаления.
Защита от XSS не строится на одной мере. Это комбинация безопасных практик разработки, корректной обработки данных, политик браузера и регулярного тестирования. Каждый уровень защиты снижает риск или ограничивает последствия.
Валидация входных данных — первый рубеж защиты. Приложение должно проверять, соответствуют ли полученные данные ожидаемому формату, и отклонять или обрабатывать те, что не соответствуют.
Что включает валидация ввода:
Подходы к фильтрации:
| Подход | Описание | Ограничения |
| Whitelist (разрешающий список) | Принимать только то, что явно разрешено | Требует четкого определения допустимых значений |
| Blacklist (запрещающий список) | Блокировать известные опасные паттерны | Легко обойти через обфускацию и кодировки |
| Sanitization | Очищать данные от потенциально опасных элементов | Не заменяет экранирование при выводе |
Важно: валидация и фильтрация ввода снижают риск, но не являются достаточной защитой от XSS сами по себе. Основная мера защиты — безопасный вывод данных в правильном контексте.
Типичная ошибка, олагаться только на фильтрацию ввода и считать задачу решенной. Злоумышленник может использовать нестандартные кодировки, разбивку строк и другие техники обхода фильтров. Поэтому фильтрация ввода должна дополняться экранированием вывода.
Это наиболее важная и базовая мера защиты от XSS. Любые данные, полученные от пользователя или из внешних источников, должны быть экранированы перед вставкой в страницу — в соответствии с контекстом вывода.
Что такое контекстное экранирование? Один и тот же символ может быть опасным в одном контексте и безопасным в другом. Поэтому экранирование должно учитывать, куда именно вставляются данные.
| Контекст вывода | Что нужно экранировать | Пример опасного символа |
| HTML-контент | Специальные HTML-символы | <, >, &, ", ' |
| HTML-атрибут | Символы, нарушающие атрибут | ", ', пробел |
| JavaScript | Символы, нарушающие строку | \, ", ', перенос строки |
| URL | Символы, нарушающие структуру URL | <, >, ", пробел |
| CSS | Символы, нарушающие CSS-выражение | (, ), ", ' |
Практические рекомендации:
Распространенные ошибки при работе с выводом:
| Ошибка | Последствие |
| Вставка данных в HTML без экранирования | Классический XSS через HTML-контент |
| Вставка данных в атрибуты без кавычек | Нарушение структуры атрибута, XSS |
| Вставка данных в JavaScript как строки без экранирования | Выход из строкового контекста, исполнение кода |
| Использование innerHTML вместо textContent | DOM-based XSS |
| Отключение автоэскейпинга в шаблонизаторе | Полная потеря защиты на уровне шаблона |
Ключевой принцип: относитесь к любым внешним данным как к потенциально опасным и всегда экранируйте их в соответствии с контекстом вывода.
Это наиболее важная и базовая мера защиты от XSS. Любые данные, полученные от пользователя или из внешних источников, должны быть экранированы перед вставкой в страницу — в соответствии с контекстом вывода.
Что такое контекстное экранирование? Один и тот же символ может быть опасным в одном контексте и безопасным в другом. Поэтому экранирование должно учитывать, куда именно вставляются данные.
| Контекст вывода | Что нужно экранировать | Пример опасного символа |
| HTML-контент | Специальные HTML-символы | <, >, &, ", ' |
| HTML-атрибут | Символы, нарушающие атрибут | ", ', пробел |
| JavaScript | Символы, нарушающие строку | \, ", ', перенос строки |
| URL | Символы, нарушающие структуру URL | <, >, ", пробел |
| CSS | Символы, нарушающие CSS-выражение | (, ), ", ' |
Практические рекомендации:
Распространенные ошибки при работе с выводом:
| Ошибка | Последствие |
| Вставка данных в HTML без экранирования | Классический XSS через HTML-контент |
| Вставка данных в атрибуты без кавычек | Нарушение структуры атрибута, XSS |
| Вставка данных в JavaScript как строки без экранирования | Выход из строкового контекста, исполнение кода |
| Использование innerHTML вместо textContent | DOM-based XSS |
| Отключение автоэскейпинга в шаблонизаторе | Полная потеря защиты на уровне шаблона |
Ключевой принцип: относитесь к любым внешним данным как к потенциально опасным и всегда экранируйте их в соответствии с контекстом вывода.
Грамотная настройка cookie и управление сессиями помогают ограничить ущерб в случае успешной эксплуатации XSS.
Ключевые атрибуты безопасности cookie:
| Атрибут | Что делает | Польза |
| HttpOnly | Запрещает доступ к cookie через JavaScript | Защищает сессионные cookie от чтения скриптом |
| Secure | Передает cookie только по HTTPS | Защищает от перехвата в сети |
| SameSite=Strict | Запрещает отправку cookie в кросс-сайтовых запросах | Снижает риск CSRF, косвенно ограничивает XSS |
| SameSite=Lax | Частичное ограничение кросс-сайтовых запросов | Баланс безопасности и функциональности |
Дополнительные меры по управлению сессиями:
Важно понимать: атрибут HttpOnly защищает cookie от прямого чтения через JavaScript, но не устраняет XSS-уязвимость. Злоумышленник может использовать исполненный скрипт для других целей — перехвата форм, подмены интерфейса, выполнения запросов от имени пользователя.
Даже при соблюдении всех практик безопасной разработки уязвимости могут появляться: после обновлений, новых интеграций, смены библиотек, рефакторинга или ошибок в кастомном коде. Регулярное тестирование безопасности — это способ находить XSS до того, как это сделает злоумышленник.
Когда проводить тестирование:
Ключевой принцип: безопасность — это процесс, а не состояние. Одноразовая проверка не гарантирует защиту при последующих изменениях продукта.
XSS часто упоминается вместе с другими популярными веб-уязвимостями. Важно понимать различия: у каждой своя механика, свои последствия и свои меры защиты.
Общая сравнительная таблица:
| Характеристика | XSS | CSRF | SQL Injection |
| Цель атаки | Браузер пользователя | Действия пользователя | База данных сервера |
| Где исполняется | В браузере жертвы | На сервере | На сервере |
| Что внедряется | JavaScript-код | Нежелательный запрос | SQL-код |
| Кто страдает | Пользователь и бизнес | Пользователь и бизнес | Сервер и данные |
| Основная защита | Экранирование вывода, CSP | CSRF-токены, SameSite | Параметризованные запросы |
XSS — злоумышленник внедряет и исполняет вредоносный скрипт в браузере пользователя в контексте доверенного сайта.
CSRF (Cross-Site Request Forgery) — злоумышленник заставляет браузер авторизованного пользователя отправить нежелательный запрос на сервер. Пользователь даже не подозревает, что от его имени выполняется какое-то действие.
Ключевое различие:
| Параметр | XSS | CSRF |
| Что делает злоумышленник | Внедряет и исполняет код | Заставляет браузер отправить запрос |
| Нужен ли скрипт на странице | Да | Нет |
| Откуда исходит угроза | Уязвимый сайт | Внешний сайт злоумышленника |
| Защита | Экранирование, CSP | CSRF-токены, SameSite cookie |
| Цель | Данные и действия пользователя | Действия от имени пользователя |
Простая аналогия:
XSS — злоумышленник проник в ваш офис и подменил документы на столе
CSRF — злоумышленник снаружи заставил вашего сотрудника подписать нужный ему документ
Важная связь: успешная XSS-атака может помочь злоумышленнику обойти CSRF-защиту, поскольку исполненный скрипт имеет доступ к CSRF-токенам на странице.
XSS направлен на браузер и интерфейс: злоумышленник воздействует на то, что видит и получает пользователь.
SQL Injection направлен на базу данных сервера: злоумышленник внедряет SQL-код в запрос к базе данных и получает возможность читать, изменять или удалять данные.
Ключевое различие:
| Параметр | XSS | SQL Injection |
| Цель атаки | Браузер пользователя | База данных сервера |
| Что внедряется | JavaScript | SQL-код |
| Где исполняется | В браузере клиента | На сервере |
| Что под угрозой | Данные пользователя, сессия | Вся база данных |
| Основная защита | Экранирование вывода | Параметризованные запросы |
Простая аналогия:
XSS — злоумышленник подменил витрину магазина: покупатели видят то, что нужно злоумышленнику
SQL Injection — злоумышленник проник на склад и получил доступ ко всем товарам и документам
Общее у XSS и SQL Injection: обе уязвимости возникают из-за небезопасной обработки пользовательских данных. Разница — в том, куда эти данные попадают: в HTML-страницу или в SQL-запрос.