Дайджесты новостей
Концептуальный Chiaroscuro натюрморт с ветхим деревянным указателем заброшенного домена и перехватом веб-трафика DeadTag.

Атака DeadTag: чем опасны забытые теги сторонних скриптов на заброшенных доменах

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

Разработчик послушно скопировал код из инструкции вендора и вставил в глобальный шаблон сайта одну неприметную строчку: <script src="https://cdn.cool-widget-service.com/bundle.js"></script>.

Маркетинговый эксперимент завершился через месяц, виджет отключили в админке сервиса, а строчка в шаблоне сайта осталась. Прошло три года. Стартап, создавший этот виджет, обанкротился и закрылся. Скрипт по ссылке тихо перестал существовать, отдавая в консоль браузера незаметную ошибку 404 Not Found. Разработчики привыкли не обращать внимания на эту красную строчку в DevTools: «Ну ругается браузер на старый домен, подумаешь! Сайт-то работает, кнопки нажимаются, заказы идут».

И вот именно в этой точке открывается колоссальная брешь в безопасности цепочки поставок (Supply Chain Attack), получившая в профессиональном сообществе кодовое имя DeadTag. Подробности этого вектора атак описаны в независимом исследовании вектора DeadTag.

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

Анатомия перехвата: как работает вектор DeadTag

Механика атаки DeadTag поражает своей циничной простотой и полной автоматизацией:

  1. Злоумышленники запускают распределенные сетевые краулеры, которые непрерывно сканируют миллионы популярных сайтов из рейтингов Alexa, Tranco и Majestic в поисках внешних ссылок на JavaScript-файлы и API-эндпоинты.
  2. Специальный анализатор проверяет регистрационный статус обнаруженных доменных имен через протокол WHOIS и авторитетные DNS-серверы.
  3. Если создатели заброшенного сервиса забыли продлить регистрацию своего доменного имени (expired domain), бот злоумышленника мгновенно выкупает освободившийся домен на открытом аукционе за копейки (обычно регистрация обходится всего в $10–50).
  4. На купленном домене поднимается веб-сервер, который по пути старого легитимного скрипта /bundle.js начинает отдавать замаскированный вредоносный JavaScript-код.
  5. Браузеры сотен тысяч посетителей твоего сайта загружают этот скрипт с «родного», много лет прописанного в HTML тега прямо в контекст твоего веб-приложения!

С точки зрения браузера этот скрипт абсолютно легитимен: он прописан разработчиками сайта, не блокируется базовыми фильтрами и исполняется с полными привилегиями твоего домена.

А дальше наступает фаза эксплуатации. Получив выполнение JavaScript в контексте твоего сайта, злоумышленник получает доступ абсолютно ко всему:

  • Атака типа Magecart (Form Grabbing): незаметный перехват номеров банковских карт, сроков действия и CVC-кодов прямо в момент ввода в форму оплаты до отправки на платежный шлюз;
  • Чтение незащищенных сессионных токенов из localStorage и sessionStorage;
  • Кража учетных записей пользователей через поддельные всплывающие модальные окна;
  • Фоновый кликджекинг и использование мощностей клиентских процессоров для распределенного майнинга.

Как выстроить глубокую эшелонированную оборону

Полагаться на человеческую память («мы помним все скрипты, которые подключали») в современных веб-приложениях смертельно опасно. Безопасность должна гарантироваться на фундаментальном уровне стандартов веб-платформы через комбинацию двух проверенных механизмов: Subresource Integrity (SRI) и строгой политики Content Security Policy (CSP).

Во-первых, технология Subresource Integrity. Любой сторонний скрипт, подключаемый с внешнего ресурса, обязан сопровождаться криптографическим хэшем его содержимого:

<!-- Безопасное подключение внешнего скрипта с контролем криптографической целостности: -->
<script
  src="https://cdn.trusted-provider.com/analytics.js"
  integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC"
  crossorigin="anonymous">
</script>

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

Во-вторых, жесткий заголовок Content-Security-Policy на стороне сервера (Nginx, Caddy, Cloudflare или Node.js):

Content-Security-Policy: default-src 'self'; script-src 'self' https://trusted-cdn.com; object-src 'none'; base-uri 'self'; require-trusted-types-for 'script';

Если в разметке твоего проекта внезапно всплывет забытый тег со старого заброшенного домена, браузер просто откажется отправлять сетевой запрос по этому адресу, потому что домен отсутствует в разрешенном белом списке директивы script-src.

Регулярно проводите ревизию внешних зависимостей, удаляйте неиспользуемые скрипты из HTML и никогда не доверяйте внешним доменам без строгого криптографического контроля!