Substitution de gabarits côté serveur
Injectez des valeurs rendues côté serveur (par exemple des expressions Go html/template `{{ .Field }}`) dans du JavaScript obfusqué par VM sans casser la chaîne d'obfuscation.
Le problème
Votre backend (Go, Rails, Django, PHP, …) sert un fichier JavaScript dont le contenu doit être partiellement rendu
à chaque requête - un point de terminaison d'API, une liste de feature flags, un état initial, un identifiant de build, un nonce. Vous obfusquez le
JS avec vmObfuscation: true, mais vous avez aussi besoin que le moteur de gabarits substitue des marqueurs dans la sortie obfusquée
après la fin de l'obfuscation. Si ces marqueurs sont absorbés dans le bytecode VM (le comportement par défaut pour les chaînes et les
identifiants), le moteur de gabarits n'a plus rien à substituer.
Quelle option choisir ?
| La valeur serveur est… | Utilisez |
|---|---|
| Une expression JS brute (littéral de tableau, objet, nombre, booléen, appel de fonction) | reservedNames + marqueur sous forme d'identifiant |
| Une chaîne, et vous maîtrisez les délimiteurs de gabarit | reservedStrings + marqueur dans un littéral de gabarit |
Une chaîne, et le moteur de gabarits impose certains délimiteurs (par exemple Go {{ .Field }}) | reservedStrings + marqueur sous forme de chaîne ou de littéral de gabarit |
Motif 1 - reservedNames avec un marqueur sous forme d'identifiant
Idéal pour : injecter des expressions JS brutes (tableaux, objets, nombres, …) sans le moindre souci d'échappement de guillemets.
Choisissez un identifiant distinctif qui n'entrera jamais en collision avec du code réel, référencez-le directement, et déclarez dans reservedNames une
expression régulière qui le reconnaît. Sous obfuscation VM, l'identifiant est routé via le tableau des expressions réservées et
apparaît tel quel dans la sortie.
Source
(function () {
var initialState = __INITIAL_STATE__;
bootstrap(initialState);
})();
Options de l'obfuscateur
JavaScriptObfuscator.obfuscate(source, {
vmObfuscation: true,
reservedNames: ['^__INITIAL_STATE__$']
});
Après obfuscation
Vous trouverez quelque part dans la sortie un tableau d'expressions réservées de ce genre :
let _r = [__INITIAL_STATE__, /* …other entries… */];
Le jeton __INITIAL_STATE__ survit au renommage des identifiants et n'est pas absorbé dans le bytecode VM.
Substitution côté serveur (exemple en Go)
tpl := template.Must(template.New("obf.js").Parse(obfuscated))
tpl.Execute(w, map[string]any{
"InitialState": map[string]any{"user": "alice", "theme": "dark"},
})
…où votre gabarit Go remplace le jeton par une expression JS brute :
{{ `__INITIAL_STATE__` }} → {{ .InitialState | toJSON }}
Résultat :
let _r = [{"user":"alice","theme":"dark"}, /* … */];
Aucun guillemet, aucun échappement - la valeur injectée est analysée par le moteur JS comme une expression ordinaire.
Motif 2 - reservedStrings avec un marqueur dans un littéral de gabarit
Idéal pour : les moteurs de gabarits de type Go / Jinja qui imposent des délimiteurs comme {{ .Field }}, lesquels se trouvent être du texte JS
valide dès lors qu'ils sont entourés d'accents graves.
Le marqueur est placé dans un littéral de gabarit à quasi unique, sans interpolation. Sous obfuscation VM, il est routé via le tableau des expressions réservées, ce qui préserve dans la sortie la forme brute entourée d'accents graves.
Source
(function () {
var featureFlags = JSON.parse(`{{.Config.FeatureFlags}}`);
applyFlags(featureFlags);
})();
Options de l'obfuscateur
Interface
Pour réserver le marqueur {{.Config.FeatureFlags}} du source ci-dessus, saisissez cette expression régulière dans le champ Reserved Strings
- avec des barres obliques inverses simples. L'interface enregistre la valeur telle quelle : contrairement à du code JS, les barres obliques inverses ne sont donc pas doublées :
\{\{[^}]+\}\}

API
JavaScriptObfuscator.obfuscate(source, {
vmObfuscation: true,
reservedStrings: ['\\{\\{[^}]+\\}\\}']
});
Après obfuscation
let _r = [`{{.Config.FeatureFlags}}`, /* … */];
Le marqueur est préservé octet pour octet, accents graves environnants compris.
Substitution côté serveur
Remplacez {{.Config.FeatureFlags}} par une chaîne JSON valide - elle se retrouvera entre accents graves à l'exécution, ce qui ne
nécessite aucun échappement des guillemets internes :
flagsJSON, _ := json.Marshal(config.FeatureFlags) // e.g. {"newCheckout":true,"darkMode":false}
out := strings.ReplaceAll(obfuscated, "{{.Config.FeatureFlags}}", string(flagsJSON))
À l'exécution : JSON.parse(`{"newCheckout":true,"darkMode":false}`) - cela fonctionne.
Motif 3 - reservedStrings avec un marqueur sous forme de chaîne entre guillemets
Idéal pour : le code source qui doit rester en ES5 (pas de littéraux de gabarit), ou les cas où l'API environnante attend un littéral de chaîne classique.
Le marqueur est un littéral de chaîne entre guillemets simples ou doubles. Sous obfuscation VM, il est routé via le
tableau des chaînes réservées, lequel est émis sous forme de tableau JS sérialisé par JSON.stringify - toujours entre guillemets doubles, quel que
soit le style de guillemets en entrée.
Source
(function () {
var tags = JSON.parse("{{.Page.Tags}}");
renderTags(tags);
})();
Options de l'obfuscateur
Interface
Pour réserver le marqueur {{.Page.Tags}} du source ci-dessus, saisissez cette expression régulière dans le champ Reserved Strings -
avec des barres obliques inverses simples. L'interface enregistre la valeur telle quelle : contrairement à du code JS, les barres obliques inverses ne sont donc pas doublées :
\{\{[^}]+\}\}

API
JavaScriptObfuscator.obfuscate(source, {
vmObfuscation: true,
reservedStrings: ['\\{\\{[^}]+\\}\\}']
});
Après obfuscation
var _rs = ["{{.Page.Tags}}", /* … */];
Substitution côté serveur
Comme le marqueur se trouve à l'intérieur d'une chaîne JS entre guillemets doubles, les caractères " internes de la charge utile JSON injectée doivent
être échappés en \" :
raw, _ := json.Marshal(page.Tags) // e.g. ["news","tech","release"]
// Escape " for embedding inside a JS double-quoted string.
escaped := strings.ReplaceAll(string(raw), `"`, `\"`)
out := strings.ReplaceAll(obfuscated, "{{.Page.Tags}}", escaped)
Sortie obtenue :
var _rs = ["[\"news\",\"tech\",\"release\"]", /* … */];
À l'exécution : JSON.parse("[\"news\",\"tech\",\"release\"]") → ["news","tech","release"].
Si vous oubliez l'échappement, le navigateur verra des guillemets non appariés et lèvera une SyntaxError. Le motif 2 contourne complètement
ce problème en recourant aux accents graves.
Plusieurs marqueurs dans un même programme
Les trois motifs se combinent. Une seule expression régulière reservedStrings avec une alternance peut reconnaître toutes les formes de marqueurs qu'émet votre
moteur de gabarits :
JavaScriptObfuscator.obfuscate(source, {
vmObfuscation: true,
reservedNames: ['^__INITIAL_STATE__$'],
reservedStrings: ['\\{\\{[^}]+\\}\\}']
});
Vous pouvez mélanger, dans un même source, marqueurs sous forme d'identifiants (pour les valeurs JS brutes) et marqueurs sous forme de chaînes (pour du JSON rendu) - choisissez au cas par cas selon ce que le serveur injectera réellement.
Notes de compatibilité
- Ne réutilisez pas les mêmes marqueurs pour les identifiants et les chaînes. Un nom réservé comme
__TOKEN__et une chaîne réservée reconnaissant__TOKEN__décrivent deux chemins de code différents (tableau des expressions réservées vs tableau des chaînes réservées). Utilisez des formes textuelles distinctes pour chacun - par exemple une conventionUPPER_SNAKEpour les marqueurs de type identifiant et une forme encadrée par des délimiteurs ({{ ... }},%{...},<<<...>>>) pour les marqueurs de type chaîne. Ainsi, un bug dans l'une des expressions régulières ne pourra pas silencieusement reconnaître l'autre. - Les expressions régulières de
reservedStringss'appliquent aux valeurs brutes des chaînes. L'expression régulière est confrontée à la valeur de la chaîne à l'exécution, et non au texte source.\{\{[^}]+\}\}reconnaît les chaînes qui contiennent{{.something}}(ou toute autre forme{{...}}). Si votre marqueur peut être entouré de contenu supplémentaire ("prefix-{{.Field}}-suffix"), l'expression régulière correspond toujours mais la chaîne entière est préservée - prévoyez votre substitution en conséquence. - Compatible avec n'importe quel moteur de gabarits. Bien que les exemples utilisent la syntaxe Go
text/template, rien dans l'intégration de javascript-obfuscator n'est spécifique à Go. Tout ce qui sait effectuer un remplacement textuel sur la sortie de l'obfuscateur convient : Rails ERB, Django, les balises courtes PHP, sed dans une chaîne d'intégration continue, etc. Choisissez des délimiteurs que votre moteur émet naturellement et qui n'entrent pas en collision avec la syntaxe JS réelle.
