Documentazione
/
Ricette
/

Sostituzione di template lato host

Sostituzione di template lato host

Pro
v6.10.0+

Inserisci valori renderizzati dal server (ad esempio segnaposto `{{ .Field }}` in stile template Go) in JavaScript offuscato con la VM senza compromettere la pipeline di offuscamento.

Il problema

Il tuo backend (Go, Rails, Django, PHP, …) serve un file JavaScript il cui contenuto deve essere in parte renderizzato a ogni richiesta: un endpoint API, un elenco di feature flag, un blob di stato iniziale, un id di build, un nonce. Offuschi il JS con vmObfuscation: true, ma hai anche bisogno che il motore di template sostituisca i segnaposto nell'output offuscato dopo la fine dell'offuscamento. reservedNames e reservedStrings mantengono un segnaposto visibile nell'output, così che possa essere sostituito. Senza di essi, un segnaposto stringa viene assorbito nel bytecode della VM e un segnaposto identificatore viene emesso in più punti riscritti, quindi il motore di template non trova nulla da sostituire oppure rompe l'output.

Valuta di caricare i valori come dati

Se puoi, evita del tutto di modificare l'output protetto: carica la configurazione di runtime come dati prima che venga eseguito il bundle protetto. Tienila in uno script separato o recuperala da un endpoint autenticato. In questo modo l'output protetto resta intatto e vmSelfDefending può rimanere attivo. I dati consegnati a un browser sono comunque visibili a quel browser.

JavaScript

Usa gli schemi seguenti quando i valori devono davvero essere sostituiti nel file offuscato.

Una nota sugli esempi in Go: eseguono una semplice sostituzione di stringhe (strings.ReplaceAll / strings.NewReplacer) sull'output offuscato e gestiscono autonomamente l'escaping, mostrato per ciascuno schema. Non passano attraverso il pacchetto html/template di Go, che applicherebbe in aggiunta il proprio escaping contestuale per JavaScript, eseguendo un doppio escaping del contenuto. Se esegui il rendering tramite html/template, elimina l'escaping manuale e lascia che il motore esegua l'escaping una sola volta.

Quale opzione scegliere?

Il valore del server è…Usa
Un valore JS grezzo (array, oggetto, numero, booleano: qualsiasi valore JSON)Schema 1 - reservedNames + segnaposto identificatore
Una stringa (il caso comune: JSON renderizzato, un id di build, un nonce)Schema 2 - reservedStrings + segnaposto template literal
Una stringa, quando il codice deve restare ES5 o l'API circostante richiede un letterale stringa tra virgoletteSchema 3 - reservedStrings + segnaposto stringa tra virgolette

La sostituzione dopo l'offuscamento è incompatibile con vmSelfDefending: true. Consulta le Note di compatibilità alla fine di questa ricetta.

Schema 1 - reservedNames con un segnaposto identificatore

Ideale per: inserire espressioni JS grezze (array, oggetti, numeri, …) senza alcun problema di escaping delle virgolette.

Scegli un identificatore distintivo che non entri mai in collisione con il codice reale, fai riferimento direttamente a esso e inserisci in reservedNames una regex che lo riconosca. Con l'offuscamento VM, l'identificatore passa attraverso l'array delle espressioni riservate e compare così com'è nell'output, ad esempio:

JavaScript

Sostituisci l'identificatore con un'espressione completa serializzata in JSON. Non incollare il valore tra virgolette o backtick: l'identificatore non si trova all'interno di un letterale stringa, quindi il valore inserito viene analizzato dal motore JS come una normale espressione. Usa un serializzatore affidabile, esegui l'escape di < quando lo script è incorporato in HTML e testa valori che contengono virgolette, backslash, ritorni a capo, backtick e ${...}.

JavaScript

Schema 2 - reservedStrings con un segnaposto template literal

Ideale per: motori di template in stile Go / Jinja che richiedono delimitatori come {{ .Field }}, che risultano essere testo JS valido quando racchiusi tra backtick.

Il segnaposto si trova all'interno di un template literal con un solo quasi e senza interpolazioni. Con l'offuscamento VM passa attraverso l'array delle espressioni riservate, preservando nell'output la forma grezza con i backtick.

Sorgente

JavaScript

Opzioni dell'offuscatore

Interfaccia

Per riservare il segnaposto {{.Config.FeatureFlags}} del sorgente qui sopra, aggiungi questa regex al campo Reserved Strings, con backslash singoli. L'interfaccia memorizza il valore così com'è, quindi, a differenza del codice JS, i backslash non vengono raddoppiati:

Testo

Campo Reserved Strings nell'interfaccia dell'offuscatore con la regex inserita usando backslash singoli

API

JavaScript

Dopo l'offuscamento

JavaScript

Il segnaposto viene preservato byte per byte, compresi i backtick che lo circondano.

Sostituzione lato host

Sostituisci {{.Config.FeatureFlags}} con una stringa JSON sottoposta a escape per un template literal. I backtick non richiedono l'escape delle " interne, ma un backslash, un backtick o ${ all'interno del payload modificherebbero o chiuderebbero comunque il letterale, quindi esegui l'escape di questi tre:

Codice

Durante l'esecuzione: JSON.parse(`{"newCheckout":true,"darkMode":false}`) funziona.

Perché preferire i template literal alle virgolette singole o doppie per i valori stringa? I backtick non richiedono l'escape di " all'interno del payload JSON. Questo è importante perché la maggior parte dei valori renderizzati dal server è JSON, e il JSON è pieno di virgolette doppie. Con un segnaposto tra virgolette doppie dovresti eseguire l'escape di ogni " interna (vedi lo Schema 3); con i backtick il payload richiede solo l'escape dei rari backslash, backtick e ${.

Schema 3 - reservedStrings con un segnaposto stringa tra virgolette

Ideale per: codice sorgente che deve restare in ES5 (senza template literal), o casi in cui l'API circostante si aspetta un normale letterale stringa.

Il segnaposto è un letterale stringa tra virgolette singole o doppie. Con l'offuscamento VM passa attraverso l'array delle stringhe riservate, che viene emesso come array JS serializzato con JSON.stringify, sempre tra virgolette doppie indipendentemente dallo stile di virgolette dell'input.

Sorgente

JavaScript

Opzioni dell'offuscatore

Interfaccia

Per riservare il segnaposto {{.Page.Tags}} del sorgente qui sopra, aggiungi questa regex al campo Reserved Strings, con backslash singoli. L'interfaccia memorizza il valore così com'è, quindi, a differenza del codice JS, i backslash non vengono raddoppiati:

Testo

Campo Reserved Strings nell'interfaccia dell'offuscatore con la regex inserita usando backslash singoli

API

JavaScript

Dopo l'offuscamento

JavaScript

Sostituzione lato host

Poiché il segnaposto si trova all'interno di una stringa JS tra virgolette doppie, il payload JSON inserito deve avere i backslash e le " interne sottoposti a escape:

Codice

Output risultante:

JavaScript

Durante l'esecuzione: JSON.parse("[\"news\",\"tech\",\"release\"]") → ["news","tech","release"].

Se dimentichi l'escape, il browser vedrà virgolette sbilanciate e genererà un SyntaxError. Lo Schema 2 evita del tutto le virgolette doppie usando i backtick.

Più segnaposto in un unico programma

Tutti e tre gli schemi si possono combinare. Una singola regex reservedStrings con un'alternanza può riconoscere ogni forma di segnaposto emessa dal tuo motore di template, in questo caso sia lo stile {{ .Field }} sia lo stile %{ .Field }:

JavaScript

Puoi combinare nello stesso sorgente segnaposto identificatore (per valori JS grezzi) e segnaposto stringa (per JSON renderizzato), scegliendo per ciascun segnaposto in base a ciò che il server inserirà effettivamente.

Note di compatibilità

vmSelfDefending rompe la sostituzione dopo l'offuscamento

VM Self Defending rileva qualsiasi modifica all'output offuscato dopo la build, compresa una legittima sostituzione di template, e il codice protetto allora si rifiuta di funzionare.

Se ti affidi alla sostituzione di template lato host, imposta vmSelfDefending: false. Lascia disattivato anche selfDefending: non ha effetto con l'offuscamento VM, ma senza la VM vieta anch'esso qualsiasi modifica all'output.

Suggerimenti sui segnaposto

  • Non riutilizzare gli stessi segnaposto per identificatori e stringhe. Un nome riservato come __TOKEN__ e una stringa riservata che corrisponde a __TOKEN__ descrivono due percorsi di codice diversi (array delle espressioni riservate e array delle stringhe riservate). Usa forme testuali distinte per ciascuno: ad esempio, una convenzione UPPER_SNAKE per i segnaposto identificatore e una forma racchiusa tra delimitatori ({{ ... }}, %{...}, <<<...>>>) per i segnaposto stringa. In questo modo un errore in una regex non può corrispondere silenziosamente all'altra.
  • Le regex di reservedStrings vengono applicate ai valori grezzi delle stringhe. La regex viene confrontata con il valore di runtime della stringa, non con il testo sorgente. \{\{[^}]+\}\} riconosce le stringhe che contengono {{.something}} (o qualsiasi altra forma {{...}}). Se il tuo segnaposto può essere circondato da altro contenuto ("prefix-{{.Field}}-suffix"), la regex corrisponde comunque, ma viene preservata l'intera stringa: pianifica la sostituzione di conseguenza.
  • Funziona con qualsiasi motore di template. Anche se gli esempi usano la sintassi di Go, nulla nell'integrazione di javascript-obfuscator è specifico di Go. Qualsiasi strumento in grado di eseguire una sostituzione a livello di stringa sull'output dell'offuscatore funzionerà: Rails ERB, Django, i tag brevi di PHP, sed in una pipeline di CI e così via. Scegli delimitatori che il tuo motore emette in modo naturale e che non entrino in collisione con la sintassi JS reale.