Substitution de gabarits côté serveur
Injectez des valeurs rendues côté serveur (par exemple des marqueurs `{{ .Field }}` dans le style des gabarits Go) 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 bloc d'é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 remplace des marqueurs dans la sortie
obfusquée après la fin de l'obfuscation. reservedNames et reservedStrings gardent un marqueur visible dans la
sortie afin qu'il puisse être remplacé. Sans elles, un marqueur de chaîne est absorbé dans le bytecode de la VM et un
marqueur d'identifiant est émis à plusieurs endroits réécrits : le moteur de gabarits ne trouve alors rien à remplacer, ou casse la sortie.
Envisagez plutôt de charger les valeurs comme des données
Si vous le pouvez, évitez complètement de modifier la sortie protégée : chargez la configuration d'exécution comme des données avant que le bundle protégé
ne s'exécute. Placez-la dans un script séparé ou récupérez-la depuis un point de terminaison authentifié. La sortie protégée reste ainsi intacte, et
vmSelfDefending peut rester activé. Dans tous les cas, les données livrées à un navigateur sont visibles par ce navigateur.
Utilisez les modèles ci-dessous lorsque les valeurs doivent réellement être substituées dans le fichier obfusqué.
Une remarque sur les exemples Go : ils effectuent un simple remplacement de chaîne (strings.ReplaceAll / strings.NewReplacer) sur
la sortie obfusquée et gèrent eux-mêmes l'échappement, montré pour chaque modèle. Ils ne passent pas par le paquet html/template
de Go - celui-ci appliquerait par-dessus son propre échappement JavaScript contextuel, ce qui échapperait deux fois la charge utile. Si vous
effectuez le rendu via html/template, supprimez l'échappement manuel et laissez le moteur échapper une seule fois.
Quelle option choisir ?
| La valeur du serveur est… | Utilisez |
|---|---|
| Une valeur JS brute (tableau, objet, nombre, booléen - toute valeur JSON) | Modèle 1 - reservedNames + marqueur de type identifiant |
| Une chaîne (le cas courant - JSON rendu, identifiant de build, nonce) | Modèle 2 - reservedStrings + marqueur dans un littéral de gabarit |
| Une chaîne, lorsque le code doit rester en ES5 ou que l'API environnante exige un littéral de chaîne entre guillemets | Modèle 3 - reservedStrings + marqueur dans une chaîne entre guillemets |
La substitution après obfuscation est incompatible avec vmSelfDefending: true. Voir
Notes de compatibilité à la fin de cette recette.
Modèle 1 - reservedNames avec un marqueur de type identifiant
Idéal pour : injecter des expressions JS brutes (tableaux, objets, nombres, …) sans aucun souci d'échappement des guillemets.
Choisissez un identifiant distinctif qui n'entrera jamais en collision avec du vrai code, référencez-le directement et ajoutez une regex qui lui
correspond dans reservedNames. Avec l'obfuscation VM, l'identifiant passe par le tableau des expressions réservées et
apparaît tel quel dans la sortie, par exemple :
Remplacez l'identifiant par une expression complète sérialisée en JSON. Ne collez pas la valeur entre guillemets ou entre backticks -
l'identifiant ne se trouve pas dans un littéral de chaîne, donc la valeur injectée est analysée par le moteur JS comme une expression
ordinaire. Utilisez un sérialiseur de confiance, échappez < lorsque le script est intégré dans du HTML, et testez des valeurs contenant
des guillemets, des barres obliques inverses, des sauts de ligne, des backticks et ${...}.
Modèle 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 une fois entourés de backticks.
Le marqueur se trouve dans un littéral de gabarit à quasi unique, sans interpolation. Avec l'obfuscation VM, il passe par le tableau des expressions réservées, ce qui préserve la forme brute entre backticks dans la sortie.
Source
Options de l'obfuscateur
Interface
Pour réserver le marqueur {{.Config.FeatureFlags}} du source ci-dessus, ajoutez cette regex au champ Reserved Strings
- avec des barres obliques inverses simples. L'interface stocke la valeur telle quelle : contrairement au code JS, les barres obliques inverses ne sont pas doublées :

API
Après l'obfuscation
Le marqueur est conservé octet pour octet, backticks environnants compris.
Substitution côté serveur
Remplacez {{.Config.FeatureFlags}} par une chaîne JSON échappée pour un littéral de gabarit. Les backticks n'exigent pas d'échapper les
" intérieurs, mais une barre oblique inverse, un backtick ou ${ dans les données modifierait ou terminerait tout de même le littéral : échappez donc
ces trois éléments :
À l'exécution : JSON.parse(`{"newCheckout":true,"darkMode":false}`) - cela fonctionne.
Pourquoi préférer les littéraux de gabarit aux guillemets simples ou doubles pour les valeurs de type chaîne ? Les backticks n'exigent pas d'échapper les "
contenus dans les données JSON. C'est important, car la plupart des valeurs rendues côté serveur sont du JSON, et le JSON regorge de guillemets
doubles. Avec un marqueur entre guillemets doubles, vous devriez échapper chaque " intérieur (voir le modèle 3) ; avec des backticks,
seules les rares barres obliques inverses, les backticks et les ${ des données doivent être échappés.
Modèle 3 - reservedStrings avec un marqueur dans une chaîne entre guillemets
Idéal pour : le code source qui doit rester en ES5 (sans 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. Avec l'obfuscation VM, il passe par le
tableau des chaînes réservées, émis sous la forme d'un tableau JS sérialisé par JSON.stringify - toujours entre guillemets doubles, quel que soit
le style de guillemets en entrée.
Source
Options de l'obfuscateur
Interface
Pour réserver le marqueur {{.Page.Tags}} du source ci-dessus, ajoutez cette regex au champ Reserved Strings -
avec des barres obliques inverses simples. L'interface stocke la valeur telle quelle : contrairement au code JS, les barres obliques inverses ne sont pas doublées :

API
Après l'obfuscation
Substitution côté serveur
Comme le marqueur se trouve dans une chaîne JS entre guillemets doubles, les barres obliques inverses et les caractères "
intérieurs des données JSON injectées doivent être échappés :
Sortie obtenue :
À 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 modèle 2 évite
complètement les guillemets doubles grâce aux backticks.
Plusieurs marqueurs dans un même programme
Les trois modèles se combinent. Une seule regex reservedStrings avec une alternative peut correspondre à toutes les formes de marqueurs que votre
moteur de gabarits émet - ici, les styles {{ .Field }} et %{ .Field } :
Vous pouvez mélanger des marqueurs de type identifiant (pour les valeurs JS brutes) et des marqueurs dans des chaînes (pour le JSON rendu) dans le même source - choisissez marqueur par marqueur en fonction de ce que le serveur injectera réellement.
Notes de compatibilité
vmSelfDefending casse la substitution après obfuscation
VM Self Defending détecte toute modification de la sortie obfusquée après sa génération, y compris une substitution de gabarit légitime, et le code protégé refuse alors de s'exécuter.
Si vous dépendez de la substitution de gabarits côté serveur, définissez vmSelfDefending: false. Laissez aussi selfDefending désactivé : il
est sans effet avec l'obfuscation VM, et sans VM il interdit lui aussi toute modification de la sortie.
Conseils sur les marqueurs
- Ne réutilisez pas les mêmes marqueurs pour les identifiants et pour les chaînes. Un nom réservé comme
__TOKEN__et une chaîne réservée correspondant à__TOKEN__décrivent deux chemins de code différents (tableau des expressions réservées contre 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 entourée de délimiteurs ({{ ... }},%{...},<<<...>>>) pour les marqueurs dans des chaînes. Ainsi, une erreur dans une regex ne peut pas correspondre silencieusement à l'autre forme. - Les regex de
reservedStringss'appliquent aux valeurs brutes des chaînes. La regex est comparée à la valeur de la chaîne à l'exécution, et non au texte source.\{\{[^}]+\}\}correspond aux chaînes qui contiennent{{.something}}(ou toute autre forme{{...}}). Si votre marqueur peut être entouré d'un autre contenu ("prefix-{{.Field}}-suffix"), la regex correspond toujours, mais c'est la chaîne entière qui est conservée - prévoyez votre substitution en conséquence. - Fonctionne avec n'importe quel moteur de gabarits. Bien que les exemples utilisent la syntaxe Go, rien dans l'intégration de javascript-obfuscator n'est propre à Go. Tout outil capable d'effectuer un remplacement de texte sur la sortie de l'obfuscateur fonctionnera : Rails ERB, Django, les short tags PHP, sed dans une chaîne de CI, etc. Choisissez des délimiteurs que votre moteur émet naturellement et qui n'entrent pas en collision avec la vraie syntaxe JS.
