XSS: почему сегодня DOM XSS часто интереснее классики

Сегодня хочу осветить тему XSS и особенно уделить внимание DOM XSS.

Так как по мне классические векторы на reflected и stored XSS в приватных программах и зрелых продуктах часто уже неплохо прикрыты: их ловят на ранних этапах, на ревью, в сканерах и при первых же волнах тестирования.

А вот DOM XSS до сих пор регулярно остаётся в тени, хотя по импакту может быть не менее неприятным. В этом посте кратко разберу основные виды XSS, отдельно подсвечу DOM XSS и в конце дам мини-итог по защите.

━━━━━━━━━━ Что такое XSS ━━━━━━━━━━

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

━━━━━━━━━━ Основные виды XSS ━━━━━━━━━━

Reflected XSS Данные приходят из запроса и сразу отражаются в ответе страницы.

Пример логики: • GET /search?q=<script>alert(1)</script>

Если параметр q без экранирования попадает в HTML, получаем XSS. Чаще всего такая атака требует перехода жертвы по подготовленной ссылке.

Stored XSS Данные сначала сохраняются на сервере, а потом отображаются другим пользователям.

Типовые места: • комментарии • профиль пользователя • название проекта • ...

Stored XSS обычно ценнее reflected, потому что payload живёт в системе и срабатывает повторно.

DOM XSS Уязвимость возникает уже в клиентском JavaScript. Сервер может вернуть безопасный HTML, но frontend сам создаёт проблему, когда берёт данные из небезопасного источника и вставляет их в опасное место DOM.

Классический пример: • данные из location.hash попали в innerHTML

━━━━━━━━━━ Видимые и слепые XSS ━━━━━━━━━━

Visible XSS — результат видно сразу: alert, изменение DOM, подмена текста, выполнение JS в текущей странице

Blind XSS — payload срабатывает позже, часто у другого пользователя, например у администратора

━━━━━━━━━━ Как работает DOM XSS ━━━━━━━━━━

DOM XSS удобно смотреть через цепочку: Source → processing → Sink

Source — откуда JS берёт данные: • location.search • location.hash • location.href • document.referrer • localStorage/sessionStorage • cookies, если их читает JS

Sink — куда данные попадают и могут выполниться как код: • innerHTML • outerHTML • document.write() • insertAdjacentHTML() • eval() • setTimeout("...")

DOM XSS появляется, когда данные из source доходят до sink без безопасной обработки.

Именно поэтому искать DOM XSS удобно через taint flow в браузере: откуда пришли данные, как преобразовались и в какой sink попали.

━━━━━━━━━━ Как DOM XSS появляется при разработке ━━━━━━━━━━

Чаще всего из-за вполне “обычных” задач: • разработчик хочет показать на странице поисковый запрос из URL • SPA использует location.hash для роутинга (маршрутизация) • данные из localStorage считают “безопасными”, потому что они локальные • postMessage принимают без нормальной валидации origin и содержимого

То есть проблема не в дырявом браузере, а в том, что пользовательский ввод попал в опасный контекст.

━━━━━━━━━━ Как защищаться от XSS ━━━━━━━━━━

Защита строится не по типу XSS, а по контексту вставки данных.

Что реально важно: • считать любой пользовательский ввод опасным • не доверять данным только потому, что они пришли из БД, localStorage или внутреннего API • экранировать данные по контексту: HTML, attribute, JS, URL • не вставлять пользовательские данные в innerHTML, outerHTML, document.write() • по возможности использовать textContent, innerText, безопасные DOM API • не использовать eval, new Function, строковые setTimeout/setInterval • валидировать и жёстко ограничивать данные из postMessage • включать CSP как дополнительный защитный слой • в шаблонизаторах и frontend-фреймворках не отключать escaping без реальной необходимости • при ревью искать именно связки source → sink, а не только payload в ответе

#AppSec #XSS #DOMXSS #StoredXSS #ReflectedXSS #WebSecurity #BugBounty #CyberSecurity

XSS: почему сегодня DOM XSS часто интереснее классики | Сетка — социальная сеть от hh.ru