Template-Substitution auf Host-Seite
Serverseitig gerenderte Werte (z. B. Go-html/template-Ausdrücke `{{ .Field }}`) in VM-obfuskiertes JavaScript einfügen, ohne die Obfuskierungs-Pipeline zu beschädigen.
Das Problem
Ihr Backend (Go, Rails, Django, PHP, …) liefert eine JavaScript-Datei aus, deren Inhalt pro Anfrage teilweise gerendert
werden muss – ein API-Endpunkt, eine Liste von Feature-Flags, ein Blob mit dem Initialzustand, eine Build-ID, eine Nonce.
Sie obfuskieren das JS mit vmObfuscation: true, benötigen aber gleichzeitig, dass die Template-Engine Platzhalter in der
obfuskierten Ausgabe nach Abschluss der Obfuskierung ersetzt. Werden die Platzhalter in VM-Bytecode aufgenommen (das ist
der Standard für Strings und Bezeichner), hat die Template-Engine nichts mehr zu ersetzen.
Welche Option ist die richtige?
| Der Serverwert ist … | Verwenden Sie |
|---|---|
| Ein roher JS-Ausdruck (Array-Literal, Objekt, Zahl, Boolean, Funktionsaufruf) | reservedNames + Bezeichner-Platzhalter |
| Ein String, und Sie kontrollieren die Template-Trennzeichen | reservedStrings + Platzhalter im Template-Literal |
Ein String, und die Template-Engine erzwingt bestimmte Trennzeichen (z. B. Go {{ .Field }}) | reservedStrings + Platzhalter als String oder Template-Literal |
Muster 1 – reservedNames mit einem Bezeichner-Platzhalter
Am besten geeignet für: das Einfügen roher JS-Ausdrücke (Arrays, Objekte, Zahlen, …) ganz ohne Sorgen um das Escapen von Anführungszeichen.
Wählen Sie einen markanten Bezeichner, der niemals mit echtem Code kollidiert, referenzieren Sie ihn direkt und tragen Sie
einen passenden regulären Ausdruck in reservedNames ein. Unter der VM-Obfuskierung wird der Bezeichner über das Array der
reservierten Ausdrücke geführt und erscheint wortwörtlich in der Ausgabe.
Quellcode
(function () {
var initialState = __INITIAL_STATE__;
bootstrap(initialState);
})();
Obfuscator-Optionen
JavaScriptObfuscator.obfuscate(source, {
vmObfuscation: true,
reservedNames: ['^__INITIAL_STATE__$']
});
Nach der Obfuskierung
Irgendwo in der Ausgabe finden Sie ein Array reservierter Ausdrücke ähnlich diesem:
let _r = [__INITIAL_STATE__, /* …other entries… */];
Das Token __INITIAL_STATE__ übersteht das Umbenennen von Bezeichnern und wird nicht in den VM-Bytecode aufgenommen.
Substitution auf Host-Seite (Go-Beispiel)
tpl := template.Must(template.New("obf.js").Parse(obfuscated))
tpl.Execute(w, map[string]any{
"InitialState": map[string]any{"user": "alice", "theme": "dark"},
})
… wobei Ihr Go-Template das Token durch einen rohen JS-Ausdruck ersetzt:
{{ `__INITIAL_STATE__` }} → {{ .InitialState | toJSON }}
Ergebnis:
let _r = [{"user":"alice","theme":"dark"}, /* … */];
Keine Anführungszeichen, kein Escapen – der eingefügte Wert wird von der JS-Engine als gewöhnlicher Ausdruck geparst.
Muster 2 – reservedStrings mit einem Platzhalter im Template-Literal
Am besten geeignet für: Template-Engines im Stil von Go oder Jinja, die Trennzeichen wie {{ .Field }} verlangen, die
in Backticks eingefasst zufällig gültiger JS-Text sind.
Der Platzhalter liegt in einem Template-Literal mit einem einzigen Quasi und ohne Interpolation. Unter der VM-Obfuskierung wird er über das Array der reservierten Ausdrücke geführt, wodurch die rohe Backtick-Form in der Ausgabe erhalten bleibt.
Quellcode
(function () {
var featureFlags = JSON.parse(`{{.Config.FeatureFlags}}`);
applyFlags(featureFlags);
})();
Obfuscator-Optionen
UI
Um den Platzhalter {{.Config.FeatureFlags}} aus dem obigen Quellcode zu reservieren, tragen Sie diesen regulären Ausdruck
in das Feld Reserved Strings ein – mit einfachen Backslashes. Die Oberfläche speichert den Wert wortwörtlich, deshalb
werden die Backslashes anders als in JS-Code nicht verdoppelt:
\{\{[^}]+\}\}

API
JavaScriptObfuscator.obfuscate(source, {
vmObfuscation: true,
reservedStrings: ['\\{\\{[^}]+\\}\\}']
});
Nach der Obfuskierung
let _r = [`{{.Config.FeatureFlags}}`, /* … */];
Der Platzhalter bleibt Byte für Byte erhalten, einschließlich der umgebenden Backticks.
Substitution auf Host-Seite
Ersetzen Sie {{.Config.FeatureFlags}} durch eine gültige JSON-Zeichenkette – sie liegt zur Laufzeit innerhalb von
Backticks, die kein Escapen innerer Anführungszeichen erfordern:
flagsJSON, _ := json.Marshal(config.FeatureFlags) // e.g. {"newCheckout":true,"darkMode":false}
out := strings.ReplaceAll(obfuscated, "{{.Config.FeatureFlags}}", string(flagsJSON))
Zur Laufzeit: JSON.parse(`{"newCheckout":true,"darkMode":false}`) – funktioniert.
Muster 3 – reservedStrings mit einem Platzhalter in Anführungszeichen
Am besten geeignet für: Quellcode, der in ES5 bleiben muss (keine Template-Literale), oder Fälle, in denen die umgebende API ein reguläres String-Literal erwartet.
Der Platzhalter ist ein String-Literal in einfachen oder doppelten Anführungszeichen. Unter der VM-Obfuskierung wird er über
das Array der reservierten Strings geführt, das als per JSON.stringify serialisiertes JS-Array ausgegeben wird – immer
in doppelten Anführungszeichen, unabhängig vom Anführungsstil der Eingabe.
Quellcode
(function () {
var tags = JSON.parse("{{.Page.Tags}}");
renderTags(tags);
})();
Obfuscator-Optionen
UI
Um den Platzhalter {{.Page.Tags}} aus dem obigen Quellcode zu reservieren, tragen Sie diesen regulären Ausdruck in das
Feld Reserved Strings ein – mit einfachen Backslashes. Die Oberfläche speichert den Wert wortwörtlich, deshalb werden die
Backslashes anders als in JS-Code nicht verdoppelt:
\{\{[^}]+\}\}

API
JavaScriptObfuscator.obfuscate(source, {
vmObfuscation: true,
reservedStrings: ['\\{\\{[^}]+\\}\\}']
});
Nach der Obfuskierung
var _rs = ["{{.Page.Tags}}", /* … */];
Substitution auf Host-Seite
Da der Platzhalter innerhalb eines JS-Strings in doppelten Anführungszeichen liegt, müssen die inneren "-Zeichen der
eingefügten JSON-Nutzlast mit \" escapt werden:
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)
Resultierende Ausgabe:
var _rs = ["[\"news\",\"tech\",\"release\"]", /* … */];
Zur Laufzeit: JSON.parse("[\"news\",\"tech\",\"release\"]") → ["news","tech","release"].
Vergessen Sie das Escapen, sieht der Browser unausgeglichene Anführungszeichen und wirft einen SyntaxError. Muster 2 umgeht
das vollständig, indem es Backticks verwendet.
Mehrere Platzhalter in einem Programm
Alle drei Muster lassen sich kombinieren. Ein einzelner reservedStrings-Ausdruck mit einer Alternation kann jede
Platzhalterform abdecken, die Ihre Template-Engine ausgibt:
JavaScriptObfuscator.obfuscate(source, {
vmObfuscation: true,
reservedNames: ['^__INITIAL_STATE__$'],
reservedStrings: ['\\{\\{[^}]+\\}\\}']
});
Sie können Bezeichner-Platzhalter (für rohe JS-Werte) und String-Platzhalter (für gerendertes JSON) im selben Quellcode mischen – wählen Sie je Platzhalter danach, was der Server tatsächlich einfügen wird.
Kompatibilitätshinweise
- Verwenden Sie Platzhalter nicht doppelt für Bezeichner und Strings. Ein reservierter Name wie
__TOKEN__und ein reservierter String, der auf__TOKEN__passt, beschreiben zwei verschiedene Codepfade (Array der reservierten Ausdrücke gegenüber Array der reservierten Strings). Verwenden Sie für beide unterschiedliche Textformen – etwa eineUPPER_SNAKE-Konvention für Bezeichner-Platzhalter und eine von Trennzeichen umschlossene Form ({{ ... }},%{...},<<<...>>>) für String-Platzhalter. So kann ein Fehler in einem der beiden regulären Ausdrücke nicht stillschweigend auf den anderen passen. reservedStrings-Ausdrücke werden gegen die rohen String-Werte geprüft. Der reguläre Ausdruck wird gegen den Laufzeitwert des Strings abgeglichen, nicht gegen den Quelltext.\{\{[^}]+\}\}passt auf Strings, die{{.something}}(oder eine andere{{...}}-Form) enthalten. Falls Ihr Platzhalter von zusätzlichem Inhalt umgeben sein kann ("prefix-{{.Field}}-suffix"), passt der Ausdruck weiterhin, aber der gesamte String bleibt erhalten – planen Sie Ihre Substitution entsprechend.- Funktioniert mit jeder Template-Engine. Auch wenn die Beispiele die Syntax von Go
text/templateverwenden, ist an der Integration von javascript-obfuscator nichts Go-spezifisch. Alles, was eine Ersetzung auf Zeichenkettenebene an der Ausgabe des Obfuscators vornehmen kann, funktioniert: Rails ERB, Django, PHP-Short-Tags, sed in einer CI-Pipeline und so weiter. Wählen Sie Trennzeichen, die Ihre Engine von sich aus ausgibt und die nicht mit echter JS-Syntax kollidieren.
