Dokumentacja
/
Przepisy
/

Telemetria i reakcje zabezpieczeń VM

Telemetria i reakcje zabezpieczeń VM

Pro
v7.4.0+

Raportuj wykrycia zabezpieczeń VM do swojego backendu za pomocą vmDefenseHook i dostosuj reakcję na każdą kategorię wykryć przy użyciu vmDefenseReaction - od w pełni nieprzerywającej działania, wyłącznie telemetrycznej wersji po taką, która natychmiast przerywa działanie na skradzionym bundle'u.

Obejrzyj

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

Obejrzyj na YouTube

Problem

Zabezpieczenia VM - vmSelfDefending, vmDebugProtection i vmDomainLock - działają lokalnie: gdy zostanie wykryty debugger, narzędzie automatyzujące, zmodyfikowane środowisko lub nieautoryzowana domena, chroniony kod przerywa działanie albo po cichu zatruwa własne wyniki. To zatrzymuje atakującego, ale domyślnie nigdy się o tym nie dowiesz. Nie sposób stwierdzić, jak często bundle jest sondowany, który detektor zadziałał ani czy zabezpieczenie nie przerywa działania legalnemu użytkownikowi.

Tę lukę wypełniają dwie opcje. Żadna z nich nie włącza zabezpieczeń - jedynie obserwują i sterują tymi, które zostały już włączone:

  • vmDefenseHook - globalny callback otrzymujący obiekt sygnału za każdym razem, gdy zabezpieczenie coś wykryje. Służy do wysyłania telemetrii do backendu.
  • vmDefenseReaction - mapa per kategoria, która wybiera, jak reaguje włączone zabezpieczenie: przerwać działanie, decoy albo nie robić nic lokalnie.

Obie opcje wprowadzono w wersji v7.1.0, ale każdy przykład na tej stronie używa formy obiektowej vmDefenseHook: { name }, która wymaga v7.4.0. Wcześniejsze wersje przyjmowały sam ciąg znaków (vmDefenseHook: '__vmDetection'); od wersji v8.0.0 ta forma jest odrzucana, więc wszędzie używaj formy obiektowej.

Przepis 1 - raportowanie wykryć do backendu

Krok 1 - zarejestruj globalną funkcję hooka, zanim wczyta się zobfuskowany bundle

Środowisko uruchomieniowe VM i jego zabezpieczenia działają przed chronionym programem, więc wiele wykryć następuje już podczas startu. Hook należy zdefiniować jako zwykłą zmienną globalną na stronie hosta, przed tagiem zobfuskowanego skryptu:

HTML

Krok 2 - wskaż go w vmDefenseHook

Opcja jest obiektem, w którym name to nazwa globalnej funkcji do wywołania (aliases jest opcjonalne - patrz niżej):

JavaScript

W panelu pole VM Defense Hook pojawia się w sekcji Ochrona zaawansowana, gdy włączone jest co najmniej jedno zabezpieczenie (vmSelfDefending, vmDebugProtection lub vmDomainLock).

Krok 3 - odbierz sygnał na backendzie

Każde wykrycie wywołuje hook z jednym obiektem signal:

  • source - konkretny detektor: headless, node, agent, agentBrowser, domain, debugger, sandbox, nativeHook, timing lub integrity. Od wersji v7.4.0 dawne detektory env i inspector raportują jako source: 'debugger'. agentBrowser raportuje w kategorii category: 'automation' i działa na targetach przeglądarkowych z włączonym vmDebugProtection (v7.9.0+).
  • category - automation, debugger, sandbox, domain, tamper lub integrity. Źródło node raportuje jako category: 'debugger' (v7.4.0+).
  • score, threshold - wynik wykrycia i przekroczony próg

Minimalny endpoint odbierający (pokazano Express; zadziała dowolny backend przyjmujący POST). Normalizuje ciało żądania do tablicy, dzięki czemu obsługuje też formę zbiorczą wysyłaną przez opisany niżej wzorzec z buforem:

JavaScript

Hook służy wyłącznie do raportowania - jego wartość zwracana jest ignorowana, a brakujący lub rzucający wyjątek hook nic po cichu nie robi. Nigdy nie może wyłączyć zabezpieczenia, więc atakujący nic nie zyska, usuwając go lub psując. Aby zmienić to, co zabezpieczenie robi, należy użyć vmDefenseReaction (Przepis 2).

Zdefiniuj hook na stronie hosta, a nie wewnątrz zobfuskowanego kodu źródłowego

W telemetrii zależy Ci na przechwyceniu każdego wykrycia, a wiele z nich następuje już podczas startu - hook zdefiniowany wewnątrz zobfuskowanego bundle'a jest rejestrowany zbyt późno, aby je przechwycić, a jeśli zostanie skompilowany do VM, będzie nieosiągalny, dopóki program się nie uruchomi. W obu przypadkach pozostaje bezpieczny (brakujący hook nic nie robi, a hook, który sam wywołuje wykrycie, nie jest ponownie wywoływany rekurencyjnie), ale dla pełnego pokrycia należy zarejestrować go z góry na stronie hosta.

Jedynym wyjątkiem jest hook reagujący wyłącznie na wykrycie w czasie wykonania - na przykład sprzątanie, gdy debugger zostanie otwarty podczas użytkowania. Taki hook może znajdować się wewnątrz zobfuskowanego bundle'a; zobacz Przepis 3.

Aby mimo to chronić logikę raportowania, zarejestrowany hook powinien pozostać jednolinijkowym buforem opróżnianym z poziomu zobfuskowanego kodu:

JavaScript

JavaScript

Zmiana nazw pól sygnału (aliasy)

Domyślne wartości source / category to nazwy opisowe, więc każdy, kto podepnie się pod callback (lub przeczyta kod wynikowy), rozpozna zabezpieczenie i to, który detektor zadziałał. aliases zmienia nazwy pól sygnału na wybrane nieprzejrzyste tokeny, stosowane wewnątrz VM przed wyemitowaniem sygnału, dzięki czemu te nazwy nigdy nie pojawiają się w kodzie wynikowym ani nie docierają do callbacku. Aplikacja zna własne mapowanie i przekazuje tokeny do backendu.

Aliasy działają per pole: każde przyjmuje key (nazwę właściwości, którą otrzyma callback); tekstowe pola nazw source i category przyjmują dodatkowo mapę values, natomiast score / threshold są liczbami i przyjmują wyłącznie key. Nieustawione wpisy zachowują nazwy domyślne.

JavaScript

W panelu sekcja Aliasy sygnałów znajduje się pod polem VM Defense Hook.

To unikanie odcisku palca, a nie tajemnica - mapowanie nadal można wywnioskować przez wielokrotne testy, więc jedyną korzyścią jest brak ujawniania stabilnych, samoopisujących się nazw.

Przepis 2 - dostosowanie domyślnych reakcji

vmDefenseReaction konfiguruje sposób reakcji każdej kategorii wykryć. Niczego nie włącza - same zabezpieczenia włączają opcje vmSelfDefending, vmDebugProtection i vmDomainLock; ta opcja wybiera jedynie, jak reaguje włączone zabezpieczenie. Jednostką kontroli jest kategoria: każdy detektor w danej kategorii wykonuje reakcję tej kategorii, a reakcja ustawiona dla kategorii, której opcja jest wyłączona, po prostu nie ma efektu.

KategoriaWłączana przezReaguje, gdy
automationvmSelfDefending lub vmDebugProtectionKodem steruje oprogramowanie, a nie człowiek: przeglądarka headless lub automatyzowana, framework do scrapowania / testowania albo agent AI do kodowania przechodzący krok po kroku przez stronę.
debuggervmDebugProtection lub vmSelfDefendingKtoś ma otwarty debugger lub inspektor narzędzi deweloperskich przeglądarki i krok po kroku analizuje działający kod, aby go zrozumieć.
sandboxvmDebugProtectionKod w ogóle nie działa w prawdziwej przeglądarce - został przeniesiony do emulowanego lub skryptowego środowiska JavaScript, aby uruchomić go i zbadać offline.
domainvmDomainLockKod działa w witrynie, która nie została autoryzowana: na hoście spoza listy dozwolonych vmDomainLock (na przykład bundle skopiowany na cudzą domenę).
tampervmSelfDefendingŚrodowisko JavaScript wokół VM zostało zmodyfikowane, aby ją obserwować lub przejąć - na przykład natywne funkcje wbudowane przeglądarki podmieniono na wersje z instrumentacją.
integrityvmSelfDefendingWłasny kod chronionego bundle'a został zmieniony lub załatany od czasu jego wygenerowania.

Klucze to sześć powyższych nazw kategorii lub default (wartość zapasowa dla kategorii nieokreślonych). Wartości to:

  • break - natychmiast przerwać działanie
  • decoy - kontynuować działanie na zatrutym stanie, po cichu produkując błędne wyniki. decoy wymaga vmDebugProtection lub vmDomainLock na targecie przeglądarkowym; w przeciwnym razie działa jak break.
  • none - nie robić nic lokalnie (wyłącznie telemetria)

Kategoria, która nie została ustawiona, wraca do wbudowanych wartości domyślnych:

JavaScript

default obejmuje każdą kategorię, łącznie z integrity i tamper, więc { default: 'none' } daje naprawdę nieprzerywającą działania wersję wyłącznie z telemetrią:

JavaScript

JavaScript

W panelu listy wyboru VM Defense Reactions pojawiają się w sekcji Ochrona zaawansowana po włączeniu zabezpieczenia; każda kategoria jest edytowalna tylko wtedy, gdy włączone jest zabezpieczenie emitujące jej detektory.

Przepis 3 - uruchom własną logikę, zanim zabezpieczenie przerwie działanie

Hook służy nie tylko do raportowania - to również jedyne pewne miejsce, w którym można uruchomić własną reakcję zanim zadziała zabezpieczenie. Gdy na działającej stronie zostanie otwarty debugger, możesz chcieć wyczyścić to, co jest na ekranie, albo zastąpić widok stroną 404 - zanim kod przerwie działanie.

Dlaczego hook zamiast kodu w innym miejscu aplikacji: break zatrzymuje cały kolejny kod bajtowy, więc sprzątanie uruchamiane po zadziałaniu zabezpieczenia - zwłaszcza gdy samo jest zobfuskowane przez VM - to dokładnie to, czego przerwanie nie pozwala wykonać. Hook uruchamia się w miejscu wykrycia przed wykonaniem reakcji, synchronicznie - więc wywołana przez niego funkcja synchroniczna kończy się jako pierwsza, a potem break zatrzymuje VM.

Zdefiniuj reakcję jako swój vmDefenseHook. Ponieważ wykrycie debugger uruchamia się w czasie wykonania - po tym, jak program się wczytał i zdefiniował hook - hook może być częścią zobfuskowanego kodu źródłowego i zostaje skompilowany do kodu bajtowego razem z resztą bundle'a. Rozgałęziaj na podstawie signal.category, aby każdy warunek otrzymał właściwą reakcję, utrzymuj pracę synchroniczną, a następnie pozwól reakcji zadziałać:

JavaScript

JavaScript

To dotyczy wykryć, które następują w trakcie działania aplikacji - zobacz Kiedy kompilacja hooka do kodu bajtowego działa poniżej.

Pamiętaj o tych kwestiach:

  • Tylko praca synchroniczna ma gwarancję ukończenia jako pierwsza. Reakcja uruchamia się na instrukcji tuż po powrocie z hooka. Wywołania typu fire-and-forget, które natychmiast oddają sterowanie, są w porządku (navigator.sendBeacon, synchroniczne modyfikacje DOM i canvas); praca zaplanowana na później - setTimeout, kontynuacja promise'a, await - już nie, a cokolwiek, co wymaga dalszego kodu bajtowego VM, nie zostanie wykonane, bo właśnie to zatrzymuje break.
  • Hook uruchamia się przed reakcją; jej nie zastępuje. Jego wartość zwracana jest ignorowana i nie może anulować, opóźnić ani zmienić tego, co robi reakcja. Służy do działania przed przerwaniem, a nie do jego zawetowania - aby zmienić samą reakcję, użyj vmDefenseReaction (Przepis 2).

Kiedy kompilacja hooka do kodu bajtowego działa

Umieszczenie hooka wewnątrz zobfuskowanego bundle'a w ten sposób działa tylko dlatego, że wykrycie debugger uruchamia się w czasie wykonania. VM uruchamia vmDefenseHook, gdy jest jeszcze aktywna, po tym jak program się wczytał i zdefiniował hook, więc skompilowany do kodu bajtowego hook zostaje zdekodowany i uruchomiony jako pierwszy, a potem następuje break. To właśnie chroni kod źródłowy samego hooka.

Nie działa dla wykryć następujących podczas startu - automation, sandbox, domain lub debugger już otwarty w chwili wczytywania strony - ponieważ w tym momencie skompilowany do kodu bajtowego hook nie jest jeszcze zdefiniowany, więc zabezpieczenie nie znajduje żadnej funkcji do wywołania. W takich przypadkach zarejestruj hook jako zwykłą zmienną globalną na stronie hosta, tak jak w Przepisie 1. W razie wątpliwości zwykła zmienna globalna na stronie hosta obejmuje każde wykrycie, które dociera do hooka; kompilacja do kodu bajtowego dodaje ochronę jedynie dla kodu źródłowego samego hooka i tylko dla wykryć w czasie wykonania.

Od telemetrii do egzekwowania

Widoczność i egzekwowanie nie muszą być wdrażane razem. Mechanizmy obronne wdrażaj w dwóch etapach: najpierw wersję, która tylko raportuje, a potem - gdy telemetria wygląda czysto - taką, która reaguje.

Krok 1 - wypuść wersję wyłącznie obserwującą

Włącz wszystkie zabezpieczenia, których planujesz używać, wskaż w vmDefenseHook swój endpoint i wyłącz wszystkie reakcje. Każdy detektor nadal działa i raportuje każde trafienie do backendu, ale nic nie przerywa działania:

JavaScript

Krok 2 - przejrzyj zebrane sygnały

Gdy wersja zobaczy już prawdziwy ruch, poszukaj wykryć wywołanych przez legalne użycie. Dwa najczęstsze:

  • trafienia automation z własnych testów end-to-end lub monitoringu dostępności - te artefakty należy budować bez zabezpieczeń, zamiast tolerować całą kategorię na produkcji.
  • trafienia domain z hosta staging lub podglądowego, którego nie uwzględniono na liście dozwolonych vmDomainLock - należy dodać ten host.

Lepiej usunąć przyczynę, niż złagodzić reakcję: każda kategoria pozostawiona na none to detektor, który atakujący może bezpiecznie zignorować.

Krok 3 - włącz reakcje

Wystarczy usunąć nadpisanie default: 'none', aby zaczęły obowiązywać wbudowane reakcje per kategoria; ta jedna linia to cała zmiana. Jeśli któraś kategoria nadal generuje fałszywe alarmy, których nie da się wyeliminować, należy pozostawić na none tylko ją (np. vmDefenseReaction: { automation: 'none' }), a resztę egzekwować.

Po włączeniu egzekwowania warto zostawić ustawiony vmDefenseHook - hook uruchamia się niezależnie od reakcji, więc zachowujesz wgląd w to, kto sonduje Twój bundle, podczas gdy zabezpieczenia działają.