Когда сканеры пропускают атаку: как Cloudflare Client-Side Security защищает интернет-магазины
Современный интернет-магазин может выглядеть абсолютно исправным, в то время как вредоносный JavaScript выполняет скрытые задачи: похищает партнерские доходы, перенаправляет поиск и клики, искажает аналитику или запрашивает у удаленного сервера следующие инструкции. Страницы загружаются, товары отображаются, а оформление заказа работает, но браузер может незаметно выполнять то, на что владелец сайта никогда не давал разрешения.
Именно эту слепую зону призвана обнаружить наша модель машинного обучения (ML) для обеспечения безопасности на стороне клиента. В этой статье рассматриваются четыре операции, включающие восемь полезных нагрузок, которые система Page Shield ML обнаружила в «дикой природе».
Обнаружение этих вредоносных полезных нагрузок происходило в автоматическом режиме; люди проверяли каждую находку только после того, как система помечала ее как подозрительную. Когда впоследствии мы проанализировали эти кампании с помощью инструментов сканирования безопасности, семь из восьми полезных нагрузок полностью отсутствовали на VirusTotal, а URLScan не вынес вредоносного вердикта ни для одной из них. При этом Page Shield ML выявила все восемь в условиях реального трафика.
Например, хотя исследования безопасности описывали более широкое семейство Lnkr еще много лет назад, одна конкретная версия полезной нагрузки индексировалась в URLScan почти два с половиной года со статусом «Без классификации» — в том числе во время прямой проверки в январе 2024 года. Только в данном случае VirusTotal зафиксировал полезную нагрузку раньше: хотя сейчас он помечает скрипт как вредоносный, в публичной истории не указано, когда этот вердикт был присвоен впервые. В то же время Page Shield ML независимо обнаружила те же самые байты прямо на витрине онлайн-ритейлера. В более общем плане хэш может быть известен задолго до того, как стоящий за ним код будет классифицирован как вредоносный. Если ваша защита ждет появления этой метки, вы уже опоздали. Вам необходима система машинного обучения, способная самостоятельно анализировать JavaScript и оценивать его в масштабе.
Действительно, увидеть файл — не значит понять его. Самое сложное заключалось в том, что четыре операции не имели универсальной сигнатуры или общего метода маскировки. Одна из них оставалась в спящем режиме до тех пор, пока устройство, страна, время, источник перехода (referrer) или состояние браузера не совпадали с ожидаемыми параметрами. Другая скрывала партнерский запрос без кликов внутри невидимого iframe. Третьи перехватывали клики, подавляли мониторинг или условно загружали дополнительный код с удаленных серверов. Чтобы обнаружить их, нужно отслеживать взаимодействие всех этих элементов: когда скрипт просыпается, что он скрывает, что перехватывает и что запрашивает дальше. Проверить страницу один раз недостаточно; как показывают эти случаи, такие скрипты созданы для того, чтобы не привлекать внимания до появления подходящей жертвы. Именно поэтому постоянный контроль браузера позволяет отличить реальное обнаружение атаки от ее полной пропуски.
Как мы обнаруживаем и классифицируем JavaScript в больших масштабах
Та же графовая нейронная сеть (GNN), которая зафиксировала четыре упомянутые в статье операции, ранее успешно выявляла вредоносные npm-пакеты и реальные скрипты Magecart для кражи платежных данных. GNN не рассматривает JavaScript как сплошной массив текста; она анализирует код как граф: синтаксическое дерево связывает символы кода и показывает, что и кого вызывает, что злоумышленник пытался скрыть и куда отправляются запросы. Эта структура помогает распознавать подозрительные паттерны при минификации, переименовании и обфускации без опоры на известный URL или сигнатуру байтов.
Те немногие скрипты, которые GNN относит к категории вредоносных (менее 0,3% всего проанализированного трафика), передаются легковесной большой языковой модели (LLM) на базе Workers AI для получения экспертного мнения в реальном времени. Это дополнительно снижает количество ложноположительных срабатываний, сохраняя при этом высокую полноту обнаружения.
Для масштабного расследования наиболее сложных скриптов мы используем группу передовых моделей, которые называем преподавателями (ансамбль автоматизированных арбитров). Эта группа включает ведущие модели примерно из шести различных семейств, в том числе модели с открытыми весами, работающие на Workers AI. Каждую из них мы запускаем в качестве агента для анализа одного и того же подозрительного скрипта в собственной изолированной независимой сессии. При необходимости агентный доступ к инструментам позволяет им использовать ограниченный интерпретатор JavaScript для разбора небольших фрагментов и выявления скрытого поведения. Вскоре мы расширим этот рабочий процесс с помощью Cloudflare Sandbox для более глубокого анализа в изолированных средах.
Передовые модели иногда расходятся в оценках, особенно при анализе сложнейших скриптов. Мы рассматриваем эти разногласия как полезный сигнал, а не как шум. Каждая оценка становится голосом, вес которого определяется баллом модели в рейтинге Artificial Analysis Intelligence Index, что формирует распределение вероятностей по четырем категориям: безопасный, кража платежных данных (magecart), другое вредоносное ПО и майнинг криптовалюты. Таким образом, специалистам по проверке нужно изучать только те скрипты, которые помечены как вредоносные или не имеют четкого большинства в две трети голосов. Затем мы возвращаем эти распределения оценок в процесс обучения GNN, помогая ей различать все более тонкие нюансы. Этот цикл обратной связи пока частично ручной, хотя мы уже начинаем его автоматизировать.
Четыре обнаруженные нами вредоносные JavaScript-операции
Эти четыре операции выполняют совершенно разные задачи: от хищения комиссионных до подделки аналитики по покупателям, за привлечение которых магазин уже заплатил. Кража комиссии не похожа на перехват данных кредитной карты; точно так же подмена поисковой выдачи отличается от кражи пароля. Если модель машинного обучения знает только один из этих трюков, она пропустит остальные. Поэтому наша система Page Shield ML должна отслеживать любые проявления вредоносного поведения.
Теперь давайте подробнее рассмотрим каждую из операций и принцип ее работы.
Операция | Влияние на клиентов | Что делает скрипт |
|---|---|---|
1) Перехватчик партнерских комиссий в нерабочее время | Перехватывает партнерские вознаграждения | Ограничения по мобильным устройствам и времени; динамический мониторинг страниц; перехват кликов; многодневный период затишья |
2) Бескликовая партнерская кража | Похищает партнерские комиссии без кликов пользователя | Внеэкранный iframe; автоклики по скрытой ссылке в качестве резервного варианта; запросы проверки IP и временные ограничения; ежечасная ротация партнеров |
3) Старый саботажник поиска, ставший бэкдором интернет-магазина | Отслеживает пользователей и открывает бэкдор для произвольного выполнения удаленного JavaScript | Блокировка старых ключевых слов; отключение через localStorage; телеметрия; загрузка удаленного кода |
4) Клоакер для платного мобильного трафика | Скрывает магазин от мобильных посетителей по рекламным кампаниям, пытается подменять рекламу и аналитику, а также прячет службу поддержки | Фильтры по хосту, области просмотра и UTM-меткам; список из 325 подстрок IP-адресов; отключает 9 инструментов мониторинга/аналитики; трекинговые маяки нулевого пикселя |
Операция 1: Перехватчик партнерских комиссий в нерабочее время
Представьте себе тихий воскресный день: покупатель со смартфона нажимает на товар. Вместо того чтобы обработать нажатие обычным образом, скрипт открывает в новой вкладке страницу товара или рекламную целевую страницу из предварительно выбранного злоумышленником списка, а исходную вкладку перенаправляет через партнерскую ссылку. Витрина магазина при этом продолжает работать как обычно. Если покупатель завершает покупку (сейчас или позже), этот обходной путь подменяет атрибуцию, приписывая продажу (и соответствующую комиссию) аккаунту, который на самом деле не привлекал этого клиента.
Убытки магазина
Магазин может выплатить незаслуженную комиссию аккаунту, который не приводил покупателя. Хуже того, если привлечение было совершено добросовестным партнером, принудительный запрос может исказить данные атрибуции, лишив партнера, выполнившего реальную работу, заслуженного кредита и потенциальной выплаты. Ущерб может выйти за рамки одной комиссии: партнеры, потерявшие доверие к системе атрибуции, могут также перестать доверять самому ритейлеру.
Цепочка атаки
Qualified mobile visitor → intercepted product tap → script-selected page opens in new tab + original tab follows attacker’s affiliate route

Как атака оставалась скрытой
Мы обнаружили пять родственных сборки скрипта: две активные и три приостановленные на момент захвата. Каждый активный вариант использует собственный набор условий перед тем, как начать действие: проверяются такие параметры, как тип устройства посетителя и местное время, факт недавнего срабатывания этого трюка, появление кнопки товара и реальный клик по ней. Этот лабиринт правил позволяет скрывать вредоносное поведение во время краткого автоматизированного визита, если специфические условия конкретного варианта не выполнены. Активные скрипты используют MutationObserver (API JavaScript) для отслеживания плиток товаров и кнопок, которые динамически появляются после первичной загрузки страницы. Это позволяет им перехватывать клики по элементам, загружающимся с задержкой, в то время как сканер, загрузивший HTML один раз и остановившийся на этом, может полностью упустить путь перенаправления.
В активных поздних вариантах скрипт перехватывает подходящий под условия клик и записывает трехдневный период затишья в localStorage (оставаясь неактивным на этом устройстве в течение нескольких дней). Затем он выполняет маневр с двумя вкладками: открывает выбранную злоумышленником страницу товара в новой вкладке, чтобы удерживать внимание покупателя, в то время как исходная вкладка совершает быстрый и незаметный переход по партнерской ссылке злоумышленника и обратно в магазин, чтобы внедрить в фоновом режиме cookie-файл атрибуции злоумышленника. Маскировка консоли и самозащитные проверки исходного кода усложняют проверку, а периоды затишья и жесткие временные рамки ограничивают частоту появления вредоносного сценария во время обычных покупок.
Следующий очищенный фрагмент демонстрирует, как полезная нагрузка перехватывает динамические плитки товаров и выполняет обходной маневр с двумя вкладками. Для улучшения читаемости мы упростили идентификаторы, переформатировали код и нейтрализовали целевые URL-адреса.
// Watch for late-rendering product elements and hook clicks
new MutationObserver((_, observer) => {
const tile = document.querySelector(TARGET_SELECTOR);
if (!tile) return;
observer.disconnect();
tile.addEventListener("click", (e) => {
// Bail out if cooldown is still active on this device
const stored = JSON.parse(localStorage.getItem(STORAGE_KEY) || "null");
if (stored && stored.expires > Date.now()) return;
e.preventDefault();
e.stopPropagation();
localStorage.setItem(
STORAGE_KEY,
JSON.stringify({ value: "tracked", expires: Date.now() + COOLDOWN_MS }),
);
// Keep shopper engaged in new tab...
window.open(target.link, "_blank");
// ... while routing original tab through the attacker's affiliate link
setTimeout(() => {
window.location.href = target.redirectUrl;
}, 200);
}); // Note: some variants added { once: true } to detach after the first tap
}).observe(document.body, { childList: true, subtree: true });
Приостановленные сборки показали, как кампания может уйти в тень без удаления самого скрипта. Их встроенная конфигурация содержала status: "paused", поэтому они прекращали работу до установки обработчиков кликов. Эти приостановленные скрипты имели собственные конфигурации периода затишья для каждого покупателя (3, 4 и 5 дней). Один из приостановленных скриптов даже содержал комментарий в истории версий, прямо указывающий на то, что кампания была приостановлена после Черной пятницы.
Для первоначальной доставки посетителям операция использовала цепочку маркетинговых поставок сайта: сторонние скрипты и менеджеры тегов, внедренные интернет-магазинами для отслеживания рекламных кампаний и аналитики. Один из подтвержденных путей доставки проходил через два вполне обычных менеджера тегов: Google Tag Manager → другой менеджер тегов → вредоносный скрипт. Именно так полезная нагрузка попадала в браузер, что, однако, не доказывает факт компрометации самих менеджеров тегов.
Злоумышленник даже замаскировал домен, на котором размещался скрипт, чтобы успешно проходить быструю маркетинговую проверку. Один из хостов доставки скрывался на виду: adtargett[.]com отличался всего одной буквой «t» от adtarget[.]com, рекламного домена, зарегистрированного в 1998 году. Похожий домен был зарегистрирован в 2025 году, и, как показала наша проверка, его главная страница представлялась как «Adtarget.com — Performance Marketing Agency». Это таймсквотинг (typosquatting): имитируя реальное рекламное агентство, хост сливался с рутинными маркетинговыми тегами и незаметно доставлял вредоносную полезную нагрузку, которая перехватывала клики покупателей и перенаправляла их по партнерским ссылкам для выплат.
Операция 2: Бескликовая партнерская кража
Если первая мошенническая схема все же требовала клика, то эта обходится и без него. Покупатель может открыть страницу бронирования, изучать варианты товаров и ни разу не нажать на рекламу. Однако в фоновом режиме скрипт уже мог отправить партнерский запрос, из-за которого последующая покупка будет выглядеть так, будто покупателя привел кто-то другой. Действительно, при выполнении условий скрипта полезная нагрузка отправляет такой запрос через скрытый iframe или ссылку, которая нажимает сама себя.
Убытки магазина
Для пострадавшего туристического бизнеса эта атака способна исказить экономику привлечения клиентов: легитимное бронирование или покупка могут быть приписаны незаслуженному партнерскому аккаунту. Код подтверждает наличие скрытых автоматизированных партнерских запросов, однако осталось ли какое-либо конкретное обращение незамеченным на практике с точки зрения завершенной атрибуции, начисления средств на аккаунт или выплаты комиссии, остается неизвестным.
Цепочка атаки
Time-gated browser → covert affiliate request (off-screen iframe) → 1-hour throttle cookie → when blocked, automated hidden-link click fallback

Как атака оставалась скрытой
Скрипт скрывает партнерский запрос с помощью двух уровней: выборочного выполнения (предполетный сетевой фильтр и почасовое расписание) и незаметной доставки (внеэкранный iframe). Первый уровень примечателен тем, что его географические метки не связаны с реальным положением дел: выбор не определяется ни местоположением покупателя, ни локацией магазина.
Сначала скрипт обращается к общедоступному сервису геолокации по IP, но игнорирует все возвращаемые им данные, включая страну покупателя. Нам не удалось выяснить, зачем ему требовался успешный ответ при полном игнорировании полученной информации; возможно, это делалось для того, чтобы запутать исследователей, или являлось пережитком более ранней версии. Интересно, что в случае сбоя запроса геолокации скрипт молча прекращает работу: цепочка промисов завершается вызовом .catch (() => {}). Хотя злой умысел не доказан, такое поведение при сбое (fail-closed) может помогать скрипту избегать изолированных сред с ограничениями сети.
Затем, вместо использования полученных данных геолокации, полезная нагрузка содержит три объекта конфигурации TradeDoubler (сети партнерского маркетинга), озаглавленные {AU, US и UK}. Эти блоки настроек встроены в код, и каждый из них содержит партнерский URL-адрес, а также время начала и окончания. Скрипт вычисляет время Asia/Kolkata с помощью JavaScript, проверяет заданные временные окна, а затем применяет фиксированные правила четных и нечетных часов для выбора одного из трех вариантов либо пропускает партнерский запрос для данного запуска. Выбор носит детерминированный характер.
В совокупности расписание и проверки состояния браузера создают избирательное выполнение на основе временных ограничений, представляющее собой разновидность клоакинга. Когда эти условия не совпадают, партнерская активность остается в спящем режиме, поэтому единичная проверка может ее не заметить.
После выбора конфигурации скрипт записывает локальный файл cookie с именем affiliateClicked_ в качестве часового ограничения на повторные попытки, чтобы не срабатывать для этого региона сразу же (это клиентское ограничение для снижения шума, а не cookie-файл атрибуции партнерской сети). Затем он загружает этот партнерский URL-адрес во внеэкранном iframe с подавленным заголовком referrer. Ифрейм является основным путем доставки, но он снабжен агрессивным резервным механизмом: если ифрейм выдает ошибку или не завершает загрузку через одну-две секунды, скрипт создает скрытую ссылку () без атрибута target и программно кликает по ней, что может привести к переходу во вкладке пользователя. Для ничего не подозревающего покупателя все выглядит нормально: он никогда не видит рекламу, ему не нужно никуда кликать, и он может закрыть вкладку так, будто ничего не произошло.
Что касается обфускации скрипта, она проста, но эффективна: даже имена свойств собираются по одному символу за раз. Следующий очищенный фрагмент демонстрирует создание полезной нагрузкой невидимого внеэкранного iframe. Ключевые идентификаторы были переименованы, а код переформатирован для удобства чтения. Целевой адрес удален.
function loadAttribution(target) {
const frame = document['c'+'r'+'e'+'a'+'t'+'e'+'E'+'l'+'e'+'m'+'e'+'n'+'t'](
'i'+'f'+'r'+'a'+'m'+'e'
);
frame['s'+'r'+'c'] = target;
frame['r'+'e'+'f'+'e'+'r'+'r'+'e'+'r'+'P'+'o'+'l'+'i'+'c'+'y'] =
'n'+'o'+'-'+'r'+'e'+'f'+'e'+'r'+'r'+'e'+'r';
frame['s'+'t'+'y'+'l'+'e']['c'+'s'+'s'+'T'+'e'+'x'+'t'] =
'w'+'i'+'d'+'t'+'h'+':'+'1'+'p'+'x'+';'+'h'+'e'+'i'+'g'+'h'+'t'+':'+'1'+'p'+'x'+';'+
'p'+'o'+'s'+'i'+'t'+'i'+'o'+'n'+':'+'a'+'b'+'s'+'o'+'l'+'u'+'t'+'e'+';'+
'l'+'e'+'f'+'t'+':'+'-'+'9'+'9'+'9'+'9'+'p'+'x'+';'+
'v'+'i'+'s'+'i'+'b'+'i'+'l'+'i'+'t'+'y'+':'