Telemetria e reazioni delle difese VM
Segnala al tuo backend i rilevamenti delle difese VM con vmDefenseHook e regola la reazione di ogni categoria di rilevamento con vmDefenseReaction - da una build puramente di telemetria che non interrompe mai nulla, a una che si blocca immediatamente su un bundle sottratto.
Guarda
Obfuscator.io Defense Reactions: Break, Decoy, and the VM Defense Hook
Il problema
Le difese VM - vmSelfDefending, vmDebugProtection e vmDomainLock - agiscono localmente: quando viene rilevato un debugger, uno strumento di automazione, un ambiente manomesso o un dominio non autorizzato, il codice protetto si blocca oppure altera silenziosamente i propri risultati. L'attaccante viene così fermato, ma per impostazione predefinita tu non lo vieni mai a sapere. Non puoi sapere con quale frequenza il tuo bundle venga sondato, quale rilevatore sia scattato né se una difesa stia bloccando un utente legittimo.
Due opzioni colmano questa lacuna. Nessuna delle due attiva alcuna difesa: si limitano a osservare e a orientare le difese già attivate:
vmDefenseHook- una callback globale che riceve un oggetto segnale ogni volta che una difesa rileva qualcosa. Usala per inviare telemetria al tuo backend.vmDefenseReaction- una mappa per categoria che seleziona come una difesa attiva debba reagire: blocco, decoy oppure nessuna azione locale.
Entrambe le opzioni sono state introdotte nella v7.1.0, ma tutti gli esempi di questa pagina usano la forma a oggetto vmDefenseHook: { name }, che richiede
la v7.4.0. Le versioni precedenti accettavano una semplice stringa (vmDefenseHook: '__vmDetection'); questa forma viene rifiutata a partire dalla v8.0.0, quindi
usa sempre la forma a oggetto.
Ricetta 1 - segnalare i rilevamenti al tuo backend
Passaggio 1 - registrare una funzione hook globale prima del caricamento del bundle offuscato
Il runtime della VM e le relative difese vengono eseguiti prima del programma protetto, per cui molti rilevamenti si verificano già in fase di avvio. Definisci quindi l'hook come una semplice variabile globale nella pagina host, prima del tag script offuscato:
Passaggio 2 - fare puntare vmDefenseHook alla funzione
L'opzione è un oggetto il cui campo name indica la funzione globale da richiamare (aliases è facoltativo, vedi più avanti):
Nella dashboard il campo VM Defense Hook compare nella sezione Protezione avanzata non appena è attiva almeno una difesa (vmSelfDefending, vmDebugProtection o vmDomainLock).
Passaggio 3 - ricevere il segnale sul tuo backend
Ogni rilevamento richiama l'hook con un singolo oggetto signal:
source- il rilevatore specifico:headless,node,agent,agentBrowser,domain,debugger,sandbox,nativeHook,timingoppureintegrity. A partire dalla v7.4.0 i precedenti rilevatorienveinspectorvengono segnalati sottosource: 'debugger'.agentBrowserviene segnalato sottocategory: 'automation'e viene eseguito sui target browser convmDebugProtection(v7.9.0+).category-automation,debugger,sandbox,domain,tamperoppureintegrity. Il sourcenodeviene segnalato sottocategory: 'debugger'(v7.4.0+).score,threshold- il punteggio del rilevamento e la soglia superata
Segue un endpoint di ricezione minimo (l'esempio utilizza Express, ma è adatto qualsiasi backend in grado di accettare una POST). Il corpo della richiesta viene normalizzato in un array, così da gestire anche la forma raggruppata inviata dal pattern con buffer illustrato più avanti:
L'hook è solo per la segnalazione - il suo valore di ritorno viene ignorato e un hook assente o che genera
un'eccezione si traduce in un'operazione nulla e silenziosa. Non può in alcun modo disattivare una difesa, per cui un
attaccante che eliminasse o compromettesse l'hook non otterrebbe alcun vantaggio. Per modificare il comportamento di
una difesa usa vmDefenseReaction (Ricetta 2).
Definire l'hook nella pagina host, non all'interno del sorgente offuscato
Per la telemetria vuoi catturare ogni rilevamento e molti scattano in fase di avvio - un hook definito all'interno del bundle offuscato viene registrato troppo tardi per intercettarli e, se viene compilato dalla VM, non è raggiungibile finché il programma non entra in esecuzione. In entrambi i casi la situazione resta sicura (un hook assente non produce effetti e un hook che a sua volta attiva un rilevamento non viene richiamato di nuovo in modo ricorsivo), ma per una copertura completa registralo in anticipo nella pagina host.
L'unica eccezione è un hook che reagisce soltanto a un rilevamento a runtime - come la pulizia quando un debugger si apre durante l'uso. Un hook di questo tipo può risiedere all'interno del bundle offuscato; vedi la Ricetta 3.
Per proteggere comunque la tua logica di segnalazione, ti basta mantenere come hook registrato un buffer di una sola riga e svuotarlo dal codice offuscato:
Rinominare i campi del segnale (alias)
I valori predefiniti di source e category sono nomi descrittivi, per cui chiunque strumenti la callback (o legga l'output) è in grado di riconoscere la protezione e il rilevatore che è scattato. aliases rinomina i campi del segnale con token opachi a tua scelta, applicati all'interno della VM prima dell'emissione del segnale, così che quei nomi non compaiano mai nell'output né raggiungano la callback. È la tua applicazione a conoscere la mappatura e a inoltrare i token al backend.
Definisci gli alias per singolo campo: ciascuno accetta una key (il nome della proprietà che la callback riceve); i campi nominali di tipo stringa source e category accettano inoltre una mappa values, mentre score e threshold sono numerici e accettano soltanto una key. Le voci non impostate mantengono i nomi predefiniti.
Nella dashboard la sezione Alias dei segnali si trova sotto il campo VM Defense Hook.
Si tratta di elusione del fingerprinting, non di segretezza: la mappatura può comunque essere dedotta con prove ripetute, per cui l'unico vantaggio consiste nel non esporre nomi stabili e autoesplicativi.
Ricetta 2 - modificare le reazioni predefinite
vmDefenseReaction configura il modo in cui reagisce ciascuna categoria di rilevamento. Non attiva nulla: le difese vengono abilitate da vmSelfDefending, vmDebugProtection e vmDomainLock, mentre questa opzione si limita a selezionare la reazione di una difesa già attiva. L'unità di controllo è la categoria: ogni rilevatore appartenente a una categoria mette in atto la reazione prevista per quella categoria, mentre una reazione impostata per una categoria la cui opzione è disattivata semplicemente non ha effetto.
| Categoria | Attivata da | Reagisce quando |
|---|---|---|
automation | vmSelfDefending oppure vmDebugProtection | Il codice è pilotato da un software anziché da una persona: un browser headless o automatizzato, un framework di scraping o di test, oppure un agente di programmazione basato su IA che percorre la pagina. |
debugger | vmDebugProtection oppure vmSelfDefending | È aperto un debugger o l'inspector degli strumenti di sviluppo del browser e qualcuno sta percorrendo passo passo il codice in esecuzione per comprenderlo. |
sandbox | vmDebugProtection | Il codice non viene eseguito in un browser reale: è stato trasferito in un ambiente JavaScript emulato o pilotato da script per essere eseguito e studiato offline. |
domain | vmDomainLock | Il codice viene eseguito su un sito non autorizzato: un host non incluso nell'elenco consentito di vmDomainLock (ad esempio il tuo bundle copiato sul dominio di terzi). |
tamper | vmSelfDefending | L'ambiente JavaScript attorno alla VM è stato modificato per osservarla o dirottarla, ad esempio sostituendo le funzioni native del browser con versioni strumentate. |
integrity | vmSelfDefending | Il codice del bundle protetto è stato modificato o corretto dopo la sua generazione. |
Le chiavi sono i sei nomi di categoria appena elencati, oppure default (un valore di ripiego per le categorie non specificate). I valori disponibili sono:
break- blocco immediatodecoy- prosecuzione dell'esecuzione su uno stato avvelenato, producendo silenziosamente risultati errati.decoyrichiedevmDebugProtectionovmDomainLocksu un target browser; altrimenti si comporta comebreak.none- nessuna azione locale (sola telemetria)
Una categoria non impostata ricade sui valori predefiniti integrati:
default interessa tutte le categorie, integrity e tamper comprese, per cui { default: 'none' } produce una build realmente non invasiva, dedicata alla sola telemetria:
Nella dashboard i selettori VM Defense Reactions compaiono nella sezione Protezione avanzata non appena una difesa è attiva; ciascuna categoria è modificabile soltanto finché è attiva una difesa che ne emette i rilevatori.
Ricetta 3 - eseguire la tua logica prima che una difesa reagisca
L'hook non è soltanto per la segnalazione - è anche l'unico punto affidabile in cui eseguire una tua risposta prima che una difesa reagisca. Quando un debugger si apre su una pagina in esecuzione, potresti voler cancellare ciò che è a schermo, oppure sostituire la vista con una pagina 404, prima che il codice si blocchi.
Perché l'hook anziché del codice altrove nell'applicazione: break arresta tutto il bytecode successivo, per cui una procedura di smontaggio eseguita dopo che una difesa è scattata - soprattutto quando è essa stessa offuscata dalla VM - è esattamente ciò che il blocco impedisce di eseguire. L'hook scatta nel punto del rilevamento prima che la reazione venga messa in atto, in modo sincrono - quindi una funzione sincrona da esso richiamata termina per prima, poi break arresta la VM.
Definisci la risposta come il tuo vmDefenseHook. Poiché il rilevamento debugger scatta a runtime - dopo che il programma è stato caricato e ha definito l'hook - l'hook può fare parte del tuo sorgente offuscato ed essere compilato in bytecode insieme al resto del bundle. Ramifica su signal.category così che a ogni condizione corrisponda la risposta corretta, mantieni sincrono il lavoro e poi lascia che la reazione venga eseguita:
Questo si applica ai rilevamenti che scattano mentre l'applicazione è in esecuzione - vedi più avanti Quando la compilazione dell'hook in bytecode funziona.
Tieni presenti i punti seguenti:
- Solo il lavoro sincrono ha la garanzia di terminare per primo. La reazione viene eseguita sull'istruzione immediatamente successiva al ritorno dell'hook. Le chiamate fire-and-forget che delegano immediatamente vanno bene (
navigator.sendBeacon, modifiche sincrone al DOM e al canvas); il lavoro pianificato per un momento successivo - unsetTimeout, la continuazione di una promise, unawait- no, e tutto ciò che richiede altro bytecode della VM non verrà eseguito, perché è proprio ciò chebreakarresta. - L'hook viene eseguito prima della reazione; non la sostituisce. Il suo valore di ritorno viene ignorato e non può annullare, ritardare o modificare ciò che fa la reazione. Usalo per agire prima del blocco, non per porvi il veto - per modificare la reazione stessa usa
vmDefenseReaction(Ricetta 2).
Quando la compilazione dell'hook in bytecode funziona
Collocare l'hook all'interno del bundle offuscato in questo modo funziona soltanto perché il rilevamento debugger scatta a runtime. La VM richiama vmDefenseHook mentre è ancora attiva, dopo che il programma è stato caricato e ha definito l'hook, quindi l'hook compilato in bytecode viene decodificato ed eseguito per primo, poi break. È questo a proteggere il sorgente stesso dell'hook.
Non funziona per i rilevamenti che scattano in fase di avvio - automation, sandbox, domain o un debugger già aperto al caricamento della pagina - perché a quel punto l'hook compilato in bytecode non è ancora definito, quindi la difesa non trova alcuna funzione da richiamare. Per questi casi, registra l'hook come una semplice variabile globale nella pagina host, come nella Ricetta 1. Nel dubbio, una semplice variabile globale nella pagina host copre ogni rilevamento che raggiunge l'hook; la compilazione in bytecode aggiunge protezione soltanto al sorgente stesso dell'hook, e soltanto per i rilevamenti a runtime.
Dalla telemetria all'applicazione delle difese
Visibilità e applicazione delle difese non devono necessariamente essere rilasciate insieme. Distribuisci le difese in due fasi: prima una build che si limita a segnalare e poi - quando la telemetria risulta pulita - una che reagisce.
Passaggio 1 - distribuire una build di sola osservazione
Attiva tutte le difese che intendi utilizzare, fai puntare vmDefenseHook al tuo endpoint e disattiva tutte le reazioni. Ogni rilevatore continua a funzionare e a segnalare al backend ciascuna occorrenza, ma nulla si blocca:
Passaggio 2 - esaminare i segnali raccolti
Dopo che la build ha ricevuto traffico reale, individua i rilevamenti provocati da un utilizzo legittimo. I due casi più frequenti:
- Occorrenze di
automationdovute ai tuoi test end-to-end o al monitoraggio della disponibilità: genera quegli artefatti senza le difese, anziché tollerare la categoria in produzione. - Occorrenze di
domaindovute a un host di staging o di anteprima dimenticato nell'elenco consentito divmDomainLock: ti basta aggiungere l'host.
Rimuovi la causa anziché attenuare una reazione: ogni categoria lasciata su none è un rilevatore che un attaccante può tranquillamente ignorare.
Passaggio 3 - attivare le reazioni
Rimuovi la sovrascrittura default: 'none' affinché si applichino le reazioni predefinite per categoria; quella singola riga è l'intera modifica. Se una categoria continua a produrre falsi positivi non eliminabili, puoi lasciare su none soltanto quella categoria (ad esempio vmDefenseReaction: { automation: 'none' }) e applicare le difese per tutte le altre.
Mantieni vmDefenseHook impostato anche dopo l'attivazione delle reazioni: l'hook scatta indipendentemente
dalla reazione, così conservi la visibilità su chi sonda il tuo bundle mentre le difese agiscono.
