Межсайтовый скриптинг на основе DOM (DOM-based XSS)

Межсайтовый скриптинг на базе DOM (DOM-based XSS) – это тип атаки, эксплуатирующий модель объектов документов (DOM, Document Object Model).

Как работает XSS на основе DOM?

DOM – это внутренняя структура данных, которая сохраняет все объекты и свойства веб-страницы. К примеру, каждый тег, используемый в HTML-коде, представляет объект DOM.

Кроме того, DOM веб-страницы содержит информацию о таких свойствах, как URL-адрес страницы и метаданные. Разработчики могут обращаться к этим объектам и свойствам с помощью JavaScript и изменять их динамически.

Модель объектов документов – это то, что помогает создавать динамические одностраничные программы. Однако это также то, что делает возможным межсайтовый скриптинг на основе DOM.

В отличие от всех других типов межсайтового скриптинга, XSS на основе DOM – это исключительно уязвимость на стороне клиента. Это означает, что полезная нагрузка никогда не достигает сервера. Вся атака проходит в веб-браузере.

Межсайтовый скриптинг на основе DOM похож на отображенный XSS, поскольку во время атаки никакая информация не сохраняется. XSS на основе DOM также осуществляется путем обмана цели, чтобы она нажала на вредоносный URL-адрес.

Источники и приемники в XSS на основе DOM

Каждая уязвимость XSS на основе DOM имеет два элемента: источник входных данных пользователя и место, куда они записываются, что называется приемником (sink).

Распространенными источниками, которыми могут манипулировать злоумышленники, являются document.URL, document.documentURI, location.href, location.search, location.*, window.name и document.referrer.

Популярными приемниками являются document.write, (element).innerHTML, eval, setTimeout, setInterval и execScript.

Чтобы JavaScript был уязвим к XSS на основе DOM, он должен получать информацию из источника, который может контролировать злоумышленник, а затем передавать ее приемнику.

Пример XSS на основе DOM

В этом примере разработчик хочет отобразить имя пользователя на странице панели инструментов (dashboard.html). Оно передается в программу как параметр в URL-адресе:

<html>
(...)
Dashboard for
<script>
   var pos=document.URL.indexOf("context=")+8;
   document.write(decodeURIComponent(document.URL.substring(pos)));
</script>
(...)
</html>

Скрипт ищет context= в URL-адресе (document.URL.indexOf(“context=”)), берет весь текст справа от него (+8 означает 8 символов справа от начала context=) и использует document.write для вставки этого текста непосредственно в HTML для интерпретации браузером.

Если вызвать этот URL-адрес:

http://www.example.com/dashboard.html?context=Thomas

На странице будет написано:

Dashboard for Thomas

Атака XSS на основе DOM

Важно: информация предоставлена исключительно для повышения осведомленности о рисках и не призывает к противоправным действиям.

Злоумышленник создает следующий URL-адрес:

http://www.example.com/dashboard.html?context=
%3c%73%63%72%69%70%74%3e%61%6c%65%72%74%28%22%4c%45
%41%56%45%20%54%48%49%53%20%50%41%47%45%21%20%59%4f
%55%20%41%52%45%20%42%45%49%4e%47%20%48%41%43%4b%45
%44%21%22%29%3b%3c%2f%73%63%72%69%70%74%3e

Длинная строка шестнадцатеричных кодов в этой полезной нагрузке является URL-кодированной формой следующего содержимого:

<script>alert("LEAVE THIS PAGE! YOU ARE BEING HACKED!");</script>

Затем злоумышленник отправляет URL цели, например, в электронном письме. Затем она нажимает на нее, браузер открывает страницу dashboard.html и запускает вредоносный скрипт. Это переписывает содержимое документа и вставляет следующий тег в HTML-код, интерпретируемый браузером:

Dashboard for <script>alert("LEAVE THIS PAGE! YOU ARE BEING HACKED!");</script>

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

Исправление

Разработчик переписывает код, используя безопасный приёмник. В результате ненадежное содержимое из источника всегда будет интерпретироваться как текст, а не как код:

<html>
(...)
Dashboard for <span id="contentholder"></span>
<script>
   var pos=document.URL.indexOf("context=")+8;
   document.getElementById("contentholder").textContent = 
       document.URL.substring(pos,document.URL.length);
</script>
(...)
</html>

Разработчик создает плейсхолдер и записывает имя пользователя не непосредственно в HTML, а в свойстве textContent объекта (используя безопасный приемник). Это гарантирует, что браузер не будет интерпретировать это содержимое как код и просто отображать его как текст.

Последствия XSS на основе DOM

Вот некоторые действия, которые могут выполнить злонамеренные хакеры на основе простого примера, приведенного ранее:

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

Как предотвратить XSS на основе DOM

Лучший способ полностью избежать уязвимостей XSS на основе DOM в коде JavaScript – использовать правильный метод вывода (безопасный приемник).

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

Также можно применять типичные методы защиты от XSS (фильтрация и экранирование) для JavaScript. К сожалению, в отличие от серверных языков, нет универсальных библиотек JavaScript, которые помогут фильтровать и экранировать данные, поэтому разработчикам приходится самостоятельно писать и поддерживать такую функциональность.

Как обнаружить XSS на основе DOM

Такие уязвимости можно обнаружить с помощью инструментов динамического тестирования безопасности приложений, таких как DAST. К примеру, это может быть Invicti (на базе Acunetix и Netsparker). Чтобы бесплатно протестировать это решение, оставьте ваши контактные данные ниже, и мы обратимся к вам:

Запрос на бесплатное тестирование Invicti

Подписаться на новости