Dokumentation
/
Rezepte
/

Template-Substitution auf Host-Seite

Template-Substitution auf Host-Seite

v6.10.0+

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-TrennzeichenreservedStrings + 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:

\{\{[^}]+\}\}

Das Feld Reserved Strings in der Obfuscator-Oberfläche mit dem eingetragenen regulären Ausdruck in einfachen Backslashes

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:

\{\{[^}]+\}\}

Das Feld Reserved Strings in der Obfuscator-Oberfläche mit dem eingetragenen regulären Ausdruck in einfachen Backslashes

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 eine UPPER_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/template verwenden, 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.