दस्तावेज़ीकरण
/
रेसिपीज़
/

होस्ट-साइड टेम्पलेट सब्स्टिट्यूशन

होस्ट-साइड टेम्पलेट सब्स्टिट्यूशन

v6.10.0+

सर्वर पर रेंडर की गई वैल्यूज़ (जैसे Go html/template के `{{ .Field }}` एक्सप्रेशन) को ऑब्फ़स्केशन पाइपलाइन तोड़े बिना VM-ऑब्फ़स्केटेड JavaScript में डालें।

समस्या

आपका बैकएंड (Go, Rails, Django, PHP, …) एक ऐसी JavaScript फ़ाइल सर्व करता है जिसकी सामग्री हर रिक्वेस्ट पर आंशिक रूप से रेंडर होनी चाहिए — कोई API एंडपॉइंट, फ़ीचर फ़्लैग्स की सूची, शुरुआती स्टेट का ब्लॉब, कोई बिल्ड आईडी, कोई nonce। आप उस JS को vmObfuscation: true से ऑब्फ़स्केट करते हैं, लेकिन आपको यह भी चाहिए कि ऑब्फ़स्केशन पूरा होने के बाद टेम्पलेट इंजन ऑब्फ़स्केटेड आउटपुट में प्लेसहोल्डर्स की जगह वैल्यू भर दे। अगर प्लेसहोल्डर्स VM बाइटकोड में समा जाएँ (स्ट्रिंग्स और आइडेंटिफ़ायर्स के लिए यही डिफ़ॉल्ट है), तो टेम्पलेट इंजन के पास बदलने को कुछ बचता ही नहीं।

मैं कौन-सा विकल्प चुनूँ?

सर्वर वैल्यू है…उपयोग करें
एक कच्चा JS एक्सप्रेशन (ऐरे लिटरल, ऑब्जेक्ट, नंबर, बूलियन, फ़ंक्शन कॉल)reservedNames + आइडेंटिफ़ायर प्लेसहोल्डर
एक स्ट्रिंग, और टेम्पलेटिंग डिलिमिटर्स आपके नियंत्रण में हैंreservedStrings + टेम्पलेट-लिटरल प्लेसहोल्डर
एक स्ट्रिंग, और टेम्पलेट इंजन कुछ ख़ास डिलिमिटर्स पर मजबूर करता है (जैसे Go का {{ .Field }})reservedStrings + स्ट्रिंग या टेम्पलेट-लिटरल प्लेसहोल्डर

पैटर्न 1 — आइडेंटिफ़ायर प्लेसहोल्डर के साथ reservedNames

किसके लिए सबसे अच्छा: कच्चे JS एक्सप्रेशन (ऐरे, ऑब्जेक्ट, नंबर, …) डालने के लिए, जहाँ कोट-एस्केपिंग की कोई चिंता न हो।

एक ऐसा विशिष्ट आइडेंटिफ़ायर चुनें जो असली कोड से कभी न टकराए, उसका सीधे संदर्भ दें, और reservedNames में उससे मेल खाता एक regex जोड़ें। VM ऑब्फ़स्केशन के तहत यह आइडेंटिफ़ायर reserved-expressions ऐरे से होकर जाता है और आउटपुट में ज्यों का त्यों दिखाई देता है।

सोर्स

(function () {
    var initialState = __INITIAL_STATE__;
    bootstrap(initialState);
})();

ऑब्फ़स्केटर विकल्प

JavaScriptObfuscator.obfuscate(source, {
    vmObfuscation: true,
    reservedNames: ['^__INITIAL_STATE__$']
});

ऑब्फ़स्केशन के बाद

आउटपुट में कहीं आपको इस तरह का एक reserved-expressions ऐरे मिलेगा:

let _r = [__INITIAL_STATE__, /* …other entries… */];

__INITIAL_STATE__ टोकन आइडेंटिफ़ायर के नाम बदलने से बच जाता है और VM बाइटकोड में नहीं समाता।

होस्ट-साइड सब्स्टिट्यूशन (Go उदाहरण)

tpl := template.Must(template.New("obf.js").Parse(obfuscated))
tpl.Execute(w, map[string]any{
    "InitialState": map[string]any{"user": "alice", "theme": "dark"},
})

…जहाँ आपका Go टेम्पलेट इस टोकन की जगह एक कच्चा JS एक्सप्रेशन रख देता है:

{{ `__INITIAL_STATE__` }} → {{ .InitialState | toJSON }}

परिणाम:

let _r = [{"user":"alice","theme":"dark"}, /* … */];

न कोट, न एस्केपिंग — डाली गई वैल्यू को JS इंजन एक साधारण एक्सप्रेशन की तरह पार्स करता है।

पैटर्न 2 — टेम्पलेट-लिटरल प्लेसहोल्डर के साथ reservedStrings

किसके लिए सबसे अच्छा: Go / Jinja शैली के टेम्पलेट इंजन, जिन्हें {{ .Field }} जैसे डिलिमिटर चाहिए और जो बैकटिक्स में लपेटे जाने पर संयोगवश वैध JS टेक्स्ट बन जाते हैं।

प्लेसहोल्डर एक सिंगल-क्वासी, बिना इंटरपोलेशन वाले टेम्पलेट लिटरल के अंदर रहता है। VM ऑब्फ़स्केशन के तहत यह reserved-expressions ऐरे से होकर जाता है और आउटपुट में कच्चा बैकटिक रूप बरकरार रहता है।

सोर्स

(function () {
    var featureFlags = JSON.parse(`{{.Config.FeatureFlags}}`);
    applyFlags(featureFlags);
})();

Obfuscator options

UI

To reserve the {{.Config.FeatureFlags}} placeholder from the source above, add this regex to the Reserved Strings field - with single backslashes. The UI stores the value verbatim, so unlike in JS code the backslashes are not doubled:

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

Reserved Strings field in the obfuscator UI with the regex entered using single backslashes

API

JavaScriptObfuscator.obfuscate(source, {
    vmObfuscation: true,
    reservedStrings: ['\\{\\{[^}]+\\}\\}']
});

After obfuscation

let _r = [`{{.Config.FeatureFlags}}`, /* … */];

The placeholder is preserved byte-for-byte, including the surrounding backticks.

Host-side substitution

Replace {{.Config.FeatureFlags}} with a valid JSON string - it will sit inside backticks at runtime, which do not require inner-quote escaping:

flagsJSON, _ := json.Marshal(config.FeatureFlags) // e.g. {"newCheckout":true,"darkMode":false}
out := strings.ReplaceAll(obfuscated, "{{.Config.FeatureFlags}}", string(flagsJSON))

At runtime: JSON.parse(`{"newCheckout":true,"darkMode":false}`) - works.

Pattern 3 - reservedStrings with a quoted string placeholder

Best for: source code that must stay in ES5 (no template literals), or cases where the surrounding API expects a regular string literal.

The placeholder is a single- or double-quoted string literal. Under VM obfuscation it routes through the reserved-strings array, which is emitted as a JSON.stringify-serialized JS array - always double-quoted regardless of the input quote style.

Source

(function () {
    var tags = JSON.parse("{{.Page.Tags}}");
    renderTags(tags);
})();

Obfuscator options

UI

To reserve the {{.Page.Tags}} placeholder from the source above, add this regex to the Reserved Strings field - with single backslashes. The UI stores the value verbatim, so unlike in JS code the backslashes are not doubled:

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

Reserved Strings field in the obfuscator UI with the regex entered using single backslashes

API

JavaScriptObfuscator.obfuscate(source, {
    vmObfuscation: true,
    reservedStrings: ['\\{\\{[^}]+\\}\\}']
});

After obfuscation

var _rs = ["{{.Page.Tags}}", /* … */];

Host-side substitution

Because the placeholder sits inside a double-quoted JS string, the injected JSON payload must have its inner " characters escaped with \":

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)

Resulting output:

var _rs = ["[\"news\",\"tech\",\"release\"]", /* … */];

At runtime: JSON.parse("[\"news\",\"tech\",\"release\"]")["news","tech","release"].

If you forget the escaping, the browser will see unbalanced quotes and throw a SyntaxError. Pattern 2 sidesteps this entirely by using backticks.

Multiple placeholders in one program

All three patterns compose. A single reservedStrings regex with an alternation can match every placeholder shape your template engine emits:

JavaScriptObfuscator.obfuscate(source, {
    vmObfuscation: true,
    reservedNames: ['^__INITIAL_STATE__$'],
    reservedStrings: ['\\{\\{[^}]+\\}\\}']
});

You can mix identifier placeholders (for raw JS values) and string placeholders (for rendered JSON) in the same source - pick per-placeholder based on what the server will actually inject.

Compatibility notes

  • Don't reuse placeholders across identifiers and strings. A reserved name like __TOKEN__ and a reserved string matching __TOKEN__ describe two different code paths (reserved-expressions array vs. reserved-strings array). Use distinct textual shapes for each - for example, an UPPER_SNAKE convention for identifier placeholders and a delimiter-wrapped shape ({{ ... }}, %{...}, <<<...>>>) for string placeholders. That way a bug in one regex can't silently match the other.
  • reservedStrings regexes run against raw string values. The regex is matched against the runtime value of the string, not the source text. \{\{[^}]+\}\} matches strings that contain {{.something}} (or any other {{...}} shape). If your placeholder might be wrapped in extra content ("prefix-{{.Field}}-suffix"), the regex still matches but the whole string is preserved - plan your substitution accordingly.
  • Works with any templating engine. Although the examples use Go text/template syntax, nothing in the javascript-obfuscator integration is Go-specific. Anything that can do a string-level replacement on the obfuscator's output will work: Rails ERB, Django, PHP short-tags, sed in a CI pipeline, etc. Choose delimiters that your engine emits naturally and that don't collide with real JS syntax.