Документация
/
Рецепты
/

Телеметрия и реакции защиты VM

Телеметрия и реакции защиты VM

Pro
v7.4.0+

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

Смотреть

Obfuscator.io Defense Reactions: Break, Decoy, and the VM Defense Hook

Смотреть на YouTube

Проблема

Средства защиты VM - vmSelfDefending, vmDebugProtection и vmDomainLock - действуют локально: при обнаружении отладчика, инструмента автоматизации, изменённой среды или неавторизованного домена защищённый код ломается или незаметно отравляет собственные результаты. Это останавливает злоумышленника, но по умолчанию вы об этом никогда не узнаёте. Вы не можете сказать, как часто ваш бандл прощупывают, какой детектор сработал и не ломает ли защита легитимного пользователя.

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

  • vmDefenseHook - глобальный коллбэк, получающий объект-сигнал каждый раз, когда защита что-то обнаруживает. Используйте его для отправки телеметрии на бэкенд.
  • vmDefenseReaction - карта по категориям, задающая, как реагирует включённая защита: сломаться, перейти в режим decoy или ничего не делать локально.

Обе опции появились в v7.1.0, но во всех примерах здесь используется объектная форма vmDefenseHook: { name }, которая требует v7.4.0. Более ранние версии принимали простую строку (vmDefenseHook: '__vmDetection'); начиная с v8.0.0 эта форма отклоняется, поэтому везде используйте объектную форму.

Рецепт 1 - сообщать о срабатываниях на бэкенд

Шаг 1 - зарегистрируйте глобальную функцию-хук до загрузки обфусцированного бандла

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

HTML

Шаг 2 - нацельте на неё vmDefenseHook

Опция - это объект, у которого name - глобальная функция для вызова (aliases необязателен, см. ниже):

JavaScript

В панели управления поле VM Defense Hook появляется в разделе Продвинутая защита, как только включена хотя бы одна защита (vmSelfDefending, vmDebugProtection или vmDomainLock).

Шаг 3 - примите сигнал на бэкенде

Каждое срабатывание вызывает хук с единственным объектом signal:

  • source - конкретный детектор: headless, node, agent, agentBrowser, domain, debugger, sandbox, nativeHook, timing или integrity. Начиная с v7.4.0 прежние детекторы env и inspector сообщают под source: 'debugger'. agentBrowser сообщает под category: 'automation' и работает в сборках для браузера с vmDebugProtection (v7.9.0+).
  • category - automation, debugger, sandbox, domain, tamper или integrity. Источник node сообщает под category: 'debugger' (v7.4.0+).
  • score, threshold - оценка срабатывания и порог, который она превысила

Минимальный принимающий эндпоинт (показан Express; подойдёт любой бэкенд, принимающий POST). Он нормализует тело к массиву, чтобы также обрабатывать пакетную форму, отправляемую паттерном с буфером ниже:

JavaScript

Хук предназначен только для отчётности - его возвращаемое значение игнорируется, а отсутствующий или бросающий исключение хук - это тихая пустая операция. Он никогда не может отключить защиту, поэтому злоумышленник, удаливший или сломавший ваш хук, ничего не выигрывает. Чтобы изменить то, что защита делает, используйте vmDefenseReaction (Рецепт 2).

Определяйте хук на странице-хосте, а не внутри обфусцированного исходника

Для телеметрии вам нужно поймать каждое срабатывание, а многие происходят на старте - хук, определённый внутри обфусцированного бандла, регистрируется слишком поздно, чтобы поймать их, и если он попадёт под VM-компиляцию, до него не добраться, пока не запустится ваша программа. Он безопасен в любом случае (отсутствующий хук - пустая операция, а хук, который сам вызывает срабатывание, не вызывается повторно рекурсивно), но для полного охвата регистрируйте его заранее на странице-хосте.

Единственное исключение - хук, который реагирует только на срабатывание во время выполнения, например очистка при открытии отладчика во время использования. Такой хук может находиться внутри обфусцированного бандла; см. Рецепт 3.

Чтобы всё же защитить логику отправки, оставьте зарегистрированный хук однострочным буфером и опустошайте его из своего обфусцированного кода:

JavaScript

JavaScript

Переименование полей сигнала (aliases)

Значения source / category по умолчанию - описательные имена, поэтому любой, кто инструментирует коллбэк (или читает результат), может распознать защиту и то, какой детектор сработал. aliases переименовывает поля сигнала в непрозрачные токены на ваш выбор, применяемые внутри VM до того, как сигнал будет выпущен, так что эти имена никогда не появляются в результате и не попадают в коллбэк. Ваше приложение знает собственное сопоставление и пересылает токены на бэкенд.

Псевдонимы задаются на каждое поле: каждое принимает key (имя свойства, которое получает коллбэк); строковые поля-имена source и category также принимают карту values, тогда как score / threshold - числа и принимают только key. Незаданные записи сохраняют имена по умолчанию.

JavaScript

В панели управления раздел Псевдонимы сигналов находится под полем VM Defense Hook.

Это уход от отпечатка, а не секретность - сопоставление всё равно можно вывести повторным тестированием, так что единственная его польза в том, чтобы не раскрывать стабильные, самоочевидные имена.

Рецепт 2 - настроить реакции по умолчанию

vmDefenseReaction настраивает, как реагирует каждая категория срабатываний. Она ничего не включает - сами защиты включаются через vmSelfDefending, vmDebugProtection и vmDomainLock; эта опция лишь выбирает, как реагирует включённая защита. Категория - единица управления: каждый детектор в категории применяет реакцию этой категории, а реакция, заданная для категории с выключенной опцией, просто не имеет эффекта.

КатегорияВключается черезРеагирует, когда
automationvmSelfDefending или vmDebugProtectionКодом управляет программа, а не человек: headless- или автоматизированный браузер, фреймворк для скрейпинга / тестирования или ИИ-агент, шагающий по странице.
debuggervmDebugProtection или vmSelfDefendingУ кого-то открыт отладчик или инспектор инструментов разработчика браузера, и он пошагово изучает выполняющийся код.
sandboxvmDebugProtectionКод вообще не выполняется в настоящем браузере - его перенесли в эмулируемую или скриптовую среду JavaScript, чтобы выполнить и изучить офлайн.
domainvmDomainLockКод выполняется на сайте, который вы не авторизовали: хост не из вашего белого списка vmDomainLock (например, ваш бандл скопирован на чужой домен).
tampervmSelfDefendingСреда JavaScript вокруг VM изменена, чтобы наблюдать за ней или перехватывать её, например встроенные объекты браузера подменены на инструментированные версии.
integrityvmSelfDefendingСобственный код защищённого бандла был отредактирован или пропатчен с момента его генерации.

Ключи - это шесть названий категорий или default (запасной вариант для неуказанных категорий). Значения:

  • break - сломаться немедленно
  • decoy - продолжать работать на отравленном состоянии, незаметно выдавая неверные результаты. decoy требует vmDebugProtection или vmDomainLock в сборке для браузера; иначе он действует как break.
  • none - ничего не делать локально (только телеметрия)

Категория, которую вы не задали, откатывается к встроенным значениям по умолчанию:

JavaScript

default охватывает каждую категорию, в том числе integrity и tamper, поэтому { default: 'none' } - это по-настоящему неразрушающая сборка, отправляющая только телеметрию:

JavaScript

JavaScript

В панели управления селекторы VM Defense Reactions появляются в разделе Продвинутая защита, как только включена защита; каждая категория редактируема лишь пока включена защита, выпускающая её детекторы.

Рецепт 3 - выполнить собственную логику до того, как защита сломается

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

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

Определите реакцию как ваш vmDefenseHook. Поскольку срабатывание debugger происходит во время выполнения - после того как ваша программа загрузилась и определила хук, - хук может быть частью вашего обфусцированного исходника и байт-кодируется вместе с остальным бандлом. Ветвитесь по signal.category, чтобы каждому условию соответствовала своя реакция, держите работу синхронной, а затем дайте реакции сработать:

JavaScript

JavaScript

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

Держите в уме следующее:

  • Гарантированно успевает завершиться первой только синхронная работа. Реакция выполняется на инструкции сразу после возврата из хука. Вызовы по принципу «запустил и забыл», отдающие управление немедленно, - это нормально (navigator.sendBeacon, синхронные правки DOM и canvas); работа, которую вы планируете на потом - setTimeout, продолжение промиса, await, - нет, и всё, чему нужен ещё VM-байт-код, не выполнится, потому что именно это и останавливает break.
  • Хук выполняется до реакции, но не заменяет её. Его возвращаемое значение игнорируется, и он не может отменить, отложить или изменить то, что делает реакция. Используйте его, чтобы действовать до слома, а не чтобы наложить на него вето - чтобы изменить саму реакцию, используйте vmDefenseReaction (Рецепт 2).

Когда байт-кодирование хука работает

Размещение хука внутри обфусцированного бандла таким образом работает только потому, что срабатывание debugger происходит во время выполнения. VM вызывает vmDefenseHook, пока она ещё жива, после того как ваша программа загрузилась и определила хук, поэтому байт-кодированный хук декодируется и выполняется первым, а затем - break. Именно это защищает исходник самого хука.

Это не работает для срабатываний, происходящих на старте - automation, sandbox, domain или уже открытый при загрузке страницы отладчик, - потому что в этот момент байт-кодированный хук ещё не определён, так что защите нечего вызывать. Для таких случаев регистрируйте хук как обычную глобальную функцию на странице-хосте, как в Рецепте 1. Если сомневаетесь, обычная глобальная функция на странице-хосте покрывает каждое срабатывание, доходящее до хука; байт-кодирование лишь добавляет защиту для исходника самого хука, и только для срабатываний во время выполнения.

От телеметрии к принуждению

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

Шаг 1 - выпустите сборку только для наблюдения

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

JavaScript

Шаг 2 - просмотрите собранные сигналы

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

  • срабатывания automation от ваших же end-to-end тестов или мониторинга доступности - собирайте эти артефакты без защит вместо того, чтобы терпеть эту категорию в продакшене.
  • срабатывания domain от staging- или preview-хоста, который вы забыли включить в белый список vmDomainLock, - добавьте хост.

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

Шаг 3 - включите реакции

Уберите переопределение default: 'none', чтобы применились встроенные реакции по категориям; эта одна строка и есть всё изменение. Если какая-то категория продолжает давать ложные срабатывания, которые вы не можете устранить, оставьте только эту категорию на none (например, vmDefenseReaction: { automation: 'none' }) и принуждайте остальные.

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