Esternalizzare la chiave di Bytecode Array Encoding
Fornisci una tua chiave di cifratura del bytecode della VM con vmBytecodeArrayEncodingKey e restituiscila durante l'esecuzione tramite un key getter, tenendola fuori dal bundle, leggendola dallo storage del client o recuperandola dal tuo backend.
Guarda
Obfuscator.io Async Executor: Async Bytecode Key Getter and Async-Only VM Virtualization
Obfuscator.io Custom Bytecode Key: Compile-Time Key and Runtime Key Getter (Cookie, Fetch, Decoy Key)
Cosa fanno queste opzioni
vmBytecodeArrayEncoding cifra l'array di bytecode della VM, in modo che non resti nell'output
in chiaro. Per impostazione predefinita la chiave di cifratura viene derivata dall'ambiente e ricostruita sul client, quindi
non devi mai gestirla. È comodo, ma il materiale della chiave resta comunque nel bundle.
Due opzioni ti permettono di togliere la chiave dal bundle e di controllarla tu stesso:
vmBytecodeArrayEncodingKey- la chiave che fornisci in fase di compilazione. Se impostata, viene usata al posto della chiave predefinita derivata dall'ambiente e non viene incorporata nell'output offuscato.vmBytecodeArrayEncodingKeyGetter- un'espressione JavaScript che restituisce quella stessa chiave durante l'esecuzione. Viene incorporata così com'è e valutata nel browser quando il codice offuscato viene caricato.
Lo scopo è la separazione: poiché la chiave non si trova nel codice, un'analisi puramente statica del bundle non può recuperarla. Deve comunque essere presente durante l'esecuzione perché il codice funzioni, quindi non è davvero segreta, ma sei tu a decidere da dove proviene e chi può vederla.
Queste due opzioni vanno usate in coppia, e l'offuscatore lo impone: impostarne una senza l'altra è un errore di convalida
in fase di build (vmBytecodeArrayEncodingKey da sola non ha alcun modo di ottenere la chiave durante l'esecuzione; un getter da solo non ha una chiave
di compilazione con cui concordare). Inoltre non hanno alcun effetto se l'array di bytecode non viene effettivamente cifrato, quindi
deve essere attivo anche vmBytecodeArrayEncoding: true, oppure vmSelfDefending: true, che forza internamente l'attivazione di vmBytecodeArrayEncoding.
Imposta entrambe le chiavi insieme a una di queste due opzioni.
Come si combinano le due chiavi
La tua chiave non viene mai usata da sola: da entrambe le parti viene combinata con una chiave interna controllata dall'offuscatore:
- In fase di compilazione.
vmBytecodeArrayEncodingKeyviene combinata con una chiave interna derivata dall'offuscatore e l'array di bytecode viene codificato con la chiave mista risultante. - Durante l'esecuzione. Il valore restituito dal tuo
vmBytecodeArrayEncodingKeyGetterviene combinato con la stessa chiave interna, ricostruita sul client a partire da vari fattori di runtime, per decodificare il bytecode.
Poiché entrambe le parti combinano la tua chiave con la chiave interna, il getter deve restituire esattamente la stessa stringa che hai passato
come vmBytecodeArrayEncodingKey. Nessuna delle due parti è sufficiente da sola: la tua chiave senza la chiave interna non può decodificare il
bytecode, e la chiave interna è inutile senza la tua. Per questo è il controllo su chi riceve la tua chiave a proteggere
davvero il codice.
Fornire la chiave durante l'esecuzione
Per impostazione predefinita il getter è sincrono: l'espressione deve restituire la chiave immediatamente quando il codice offuscato
viene caricato. Leggila da una qualsiasi fonte già presente sul client: un cookie, localStorage, una variabile globale o
un elemento DOM inserito dal server.
La chiave deve esistere prima che venga eseguito il codice offuscato:
Le altre fonti sincrone funzionano allo stesso modo: scegli quella che la tua app già popola:
Non mettere la chiave nello stesso file o script del codice offuscato. Inserirla lì vanifica completamente lo scopo: un'analisi
statica del bundle recupererebbe sia il codice sia la sua chiave. Conservala in una fonte separata e inserisci la
vmBytecodeArrayEncodingKey di compilazione da una variabile d'ambiente o da un segreto, invece di includerla in un commit.
Recuperare la chiave dal tuo backend (asincrono)
Richiede vmAsyncExecutor · v7.3.0+Un getter sincrono può leggere solo ciò che è già presente sul client. Per recuperare la chiave dal tuo server, così da poterla
proteggere con l'autenticazione e revocarla, il getter deve essere asincrono, e questo richiede
vmAsyncExecutor. Con Async Executor attivo, il getter può restituire una
Promise e la VM la attende prima di essere eseguita.
Attivare vmAsyncExecutor restringe anche ciò che viene virtualizzato: in questa modalità solo le funzioni async più esterne vengono
compilate nella VM, mentre il codice sincrono non viene virtualizzato (il resto dell'offuscamento si applica comunque). Se il tuo programma è per lo più sincrono, racchiudi il codice che vuoi
proteggere in una funzione async in modo che venga comunque coperto; consulta vmAsyncExecutor
per la regola completa.
Un getter che restituisce una Promise richiede vmAsyncExecutor. Questo non può essere verificato in fase di build, quindi un getter con Promise
e vmAsyncExecutor disattivato fallisce durante l'esecuzione.
Sul server, decidi quale chiave restituire in base a ciò di cui la tua applicazione si fida: una sessione convalidata, un
controllo di licenza e così via. Origin o Referer da soli non autenticano un chiamante, e le richieste GET dalla stessa origine
possono omettere Origin. Il trucco: invece di rifiutare i chiamanti non attendibili, restituisci una chiave sbagliata (VM_DECOY_KEY qui sotto).
Il codice protetto allora fallisce da solo (errori, risultati errati o una pagina che smette di rispondere), il che è più discreto di un evidente
401 che dice a un attaccante esattamente cosa aggirare.
Disattiva la cache delle risposte, così la chiave di un chiamante non viene mai servita a un altro. Associa le chiavi alla versione corretta della build e distribuisci chiavi e bundle insieme. Un client che riceve la chiave reale può comunque esaminarla durante l'esecuzione.
Servi da questo endpoint esattamente la stessa stringa che hai passato come vmBytecodeArrayEncodingKey in fase di build. Il getter
qui sopra recupera un URL relativo (/api/vm-key), quindi una copia del bundle ospitata su un'altra origine richiede /api/vm-key
a quell'origine e non riceve mai la tua chiave; la chiave esca è ciò che riceve un chiamante che raggiunge il tuo endpoint
ma senza una sessione attendibile (una richiesta non autenticata, un bundle sottratto e servito tramite proxy attraverso la tua origine). In entrambi i casi la
chiave reale non arriva mai e il codice protetto non viene eseguito.
Cosa sia considerato "valido" dipende interamente dall'applicazione: una sessione autenticata, una licenza firmata o una qualsiasi
combinazione. Qualunque cosa produca la chiave, racchiudila in una Promise e l'executor asincrono la attenderà prima di eseguire
la VM.
Quando la chiave non corrisponde
Il codice offuscato funziona solo quando il getter restituisce esattamente la stessa chiave usata durante l'offuscamento. Se le chiavi
sono diverse, o se il getter restituisce undefined, null o una stringa vuota, il codice fallisce durante l'esecuzione: produce risultati
errati, genera un normale errore di runtime o smette di rispondere.
Non esiste deliberatamente un messaggio di errore distinto e specifico per la chiave: una chiave errata è indistinguibile da qualsiasi altro errore di runtime. Quindi, quando un bundle protetto dalla VM genera errori, restituisce risultati errati o si blocca solo da quando usi questa opzione, controlla prima il percorso della chiave: che il getter venga risolto nella pagina, restituisca una stringa non vuota e restituisca lo stesso valore usato per la build.
