// Безопасность / Веб

XSS: межсайтовый скриптинг — типы, атаки и защита

XSS — межсайтовый скриптинг: типы и защита

XSS (Cross-Site Scripting, межсайтовый скриптинг) — внедрение чужого JavaScript, который выполняется в браузере жертвы в контексте вашего сайта. Через XSS крадут сессии и токены, подделывают интерфейс, проводят фишинг прямо на легитимном домене и совершают действия от имени пользователя. Несмотря на возраст, XSS остаётся в OWASP Top 10 2021 (категория A03: Injection) и входит в топ выплат почти на всех bug bounty программах. Это одна из самых частых находок на пентесте веб-приложений.

Три типа XSS — с примерами полезной нагрузки

1. Reflected (отражённый)

Скрипт передаётся в запросе и сразу «отражается» в ответе. Классический пример — поиск, который выводит запрос без экранирования:

https://site.com/search?q=

Жертву заманивают по ссылке (через письмо, мессенджер, рекламу). Опасность ограничена тем, что нужна активная доставка ссылки.

2. Stored (хранимый) — самый опасный

Скрипт сохраняется на сервере — в комментарии, имени профиля, отзыве, поле адреса — и выполняется у каждого, кто открывает страницу. Ссылка не нужна: достаточно, чтобы жертва зашла на заражённую страницу. Один такой XSS в админ-панели = компрометация всех администраторов.

3. DOM-based

Уязвимость целиком на стороне клиента: небезопасная работа JavaScript с данными. Источник (source) — например location.hash, приёмник (sink) — innerHTML:

// ❌ УЯЗВИМО: данные из URL напрямую в HTML
document.getElementById("out").innerHTML = location.hash.slice(1);
// атака: site.com/#

DOM-XSS особенно актуален для SPA на React, Vue, Angular, где логика вынесена в браузер.

Что реально делают через XSS

  • Кража сессии. Отправка document.cookie на сервер атакующего (если нет флага HttpOnly).
  • Кража токенов из localStorage. SPA часто хранят JWT в localStorage — он полностью доступен из JS.
  • Действия от имени жертвы. Скрипт делает запросы с её правами (перевод, смена email, создание админа).
  • Кейлоггер и фейковые формы. Перехват вводимых логина/пароля прямо на настоящем домене.
  • BeEF-хук. Полный контроль над браузером жертвы через фреймворк эксплуатации.

Защита: пять слоёв, а не один фильтр

XSS не закрывается «чёрным списком запрещённых слов» — это тупиковый путь, обходится десятками способов. Работает многослойная защита:

  1. Контекстное экранирование вывода. Кодируйте данные по месту вставки — HTML, атрибут, JS, URL требуют разного экранирования. Используйте API фреймворка, а не ручную склейку строк.
  2. Content Security Policy (CSP). Заголовок, который запрещает выполнение постороннего скрипта даже при наличии инъекции.
  3. Безопасные API вместо innerHTML. В React/Vue избегайте dangerouslySetInnerHTML/v-html; для очистки HTML — библиотека DOMPurify.
  4. HttpOnly и Secure на cookie сессии. Тогда даже сработавший XSS не украдёт сессионную куку.
  5. Валидация ввода как дополнительный барьер (например, email действительно похож на email).

Пример строгой CSP, которая нейтрализует большинство XSS:

Content-Security-Policy: default-src 'self'; script-src 'self'; object-src 'none'; base-uri 'none'; frame-ancestors 'none'

И безопасная очистка пользовательского HTML (например, для комментариев с форматированием):

import DOMPurify from "dompurify";
el.innerHTML = DOMPurify.sanitize(userHtml, { ALLOWED_TAGS: ["b","i","a","p","ul","li"] });

Экспертное наблюдение: самые дорогие XSS мы находим не в блоге, а там, где данные проходят «служебным» путём — в письмах-уведомлениях, PDF-генераторах, экспортах и админ-логах. Разработчик экранировал вывод в шаблоне сайта, но забыл про рассылку, которую читает бухгалтер или админ.

Как это тестируется

Найти XSS во всех контекстах вывода можно только ручной проверкой каждой точки ввода: формы, параметры URL, заголовки, загружаемые файлы, imported-данные. Для SPA отдельно анализируется клиентская логика (source → sink). Мы делаем это на пентесте веб-приложений и пентесте SPA.

На вашем сайте точно нет XSS?

Проверим все точки ввода и контексты вывода — reflected, stored и DOM-based — и покажем, как их закрыть.

Заказать пентест →

Читайте также: IDOR на практике, Пентест SPA.

← назад в блог