Dokumentasi
/
Resep
/

Substitusi Template di Sisi Host

Substitusi Template di Sisi Host

v6.10.0+

Injeksikan nilai hasil render server (mis. ekspresi Go html/template `{{ .Field }}`) ke dalam JavaScript hasil obfuskasi VM tanpa merusak pipeline obfuskasi.

Masalahnya

Backend Anda (Go, Rails, Django, PHP, …) menyajikan sebuah berkas JavaScript yang isinya harus dirender sebagian per-permintaan - sebuah endpoint API, daftar feature flag, blob state awal, sebuah build id, sebuah nonce. Anda mengobfuskasi JS tersebut dengan vmObfuscation: true, tetapi Anda juga membutuhkan template engine untuk mengganti placeholder pada keluaran hasil obfuskasi setelah obfuskasi selesai. Jika placeholder tersebut terserap ke dalam bytecode VM (bawaan untuk string dan pengenal), template engine tidak punya apa pun untuk digantikan.

Opsi mana yang saya pilih?

Nilai dari server berupa…Gunakan
Sebuah ekspresi JS mentah (literal larik, objek, angka, boolean, pemanggilan fungsi)reservedNames + placeholder pengenal
Sebuah string, dan Anda mengendalikan delimiter templating-nyareservedStrings + placeholder literal template
Sebuah string, dan template engine memaksa delimiter tertentu (mis. Go {{ .Field }})reservedStrings + placeholder string atau literal template

Pola 1 - reservedNames dengan placeholder pengenal

Terbaik untuk: menginjeksikan ekspresi JS mentah (larik, objek, angka, …) tanpa kekhawatiran soal escaping tanda kutip.

Pilih sebuah pengenal khas yang tidak akan pernah bertabrakan dengan kode nyata, rujuk secara langsung, dan daftarkan sebuah regex yang mencocokkannya di reservedNames. Di bawah obfuskasi VM, pengenal tersebut dirutekan melalui larik reserved-expressions dan muncul apa adanya di keluaran.

Sumber

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

Opsi obfuscator

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

Setelah obfuskasi

Di suatu tempat pada keluaran, Anda akan menemukan sebuah larik reserved-expressions yang mirip dengan:

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

Token __INITIAL_STATE__ selamat dari penggantian nama pengenal dan tidak terserap ke dalam bytecode VM.

Substitusi sisi host (contoh Go)

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

…di mana template Go Anda mengganti token tersebut dengan sebuah ekspresi JS mentah:

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

Hasil:

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

Tanpa tanda kutip, tanpa escaping - nilai yang diinjeksikan diurai oleh mesin JS sebagai ekspresi biasa.

Pola 2 - reservedStrings dengan placeholder literal template

Terbaik untuk: template engine bergaya Go / Jinja yang memerlukan delimiter seperti {{ .Field }} yang kebetulan valid sebagai teks JS ketika dibungkus dalam backtick.

Placeholder berada di dalam literal template yang berkuasi-tunggal, tanpa interpolasi. Di bawah obfuskasi VM, ini dirutekan melalui larik reserved-expressions, sehingga bentuk backtick mentahnya dipertahankan di keluaran.

Sumber

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

Opsi obfuscator

UI

Untuk mereservasi placeholder {{.Config.FeatureFlags}} dari sumber di atas, tambahkan regex ini ke field Reserved Strings

  • dengan backslash tunggal. UI menyimpan nilainya apa adanya, sehingga tidak seperti pada kode JS, backslash-nya tidak digandakan:
\{\{[^}]+\}\}

Field Reserved Strings pada UI obfuscator dengan regex yang dimasukkan menggunakan backslash tunggal

API

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

Setelah obfuskasi

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

Placeholder tersebut dipertahankan bita demi bita, termasuk backtick di sekitarnya.

Substitusi sisi host

Ganti {{.Config.FeatureFlags}} dengan sebuah string JSON yang valid - string tersebut akan berada di dalam backtick saat runtime, yang tidak memerlukan escaping tanda kutip di dalamnya:

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

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

Pola 3 - reservedStrings dengan placeholder string berkutip

Terbaik untuk: kode sumber yang harus tetap ES5 (tanpa literal template), atau kasus di mana API di sekitarnya mengharapkan sebuah literal string biasa.

Placeholder adalah literal string berkutip tunggal atau ganda. Di bawah obfuskasi VM, ini dirutekan melalui larik reserved-strings, yang dikeluarkan sebagai larik JS yang diserialisasi dengan JSON.stringify - selalu berkutip ganda tanpa memandang gaya kutip masukannya.

Sumber

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

Opsi obfuscator

UI

Untuk mereservasi placeholder {{.Page.Tags}} dari sumber di atas, tambahkan regex ini ke field Reserved Strings - dengan backslash tunggal. UI menyimpan nilainya apa adanya, sehingga tidak seperti pada kode JS, backslash-nya tidak digandakan:

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

Field Reserved Strings pada UI obfuscator dengan regex yang dimasukkan menggunakan backslash tunggal

API

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

Setelah obfuskasi

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

Substitusi sisi host

Karena placeholder berada di dalam string JS berkutip ganda, payload JSON yang diinjeksikan harus memiliki karakter " di dalamnya yang di-escape dengan \":

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)

Keluaran hasilnya:

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

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

Jika Anda lupa escaping-nya, peramban akan melihat tanda kutip yang tidak seimbang dan melempar SyntaxError. Pola 2 menghindari hal ini sepenuhnya dengan menggunakan backtick.

Beberapa placeholder dalam satu program

Ketiga pola dapat dipadukan. Satu regex reservedStrings dengan alternasi dapat mencocokkan setiap bentuk placeholder yang dikeluarkan template engine Anda:

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

Anda dapat mencampur placeholder pengenal (untuk nilai JS mentah) dan placeholder string (untuk JSON hasil render) dalam sumber yang sama - pilih per-placeholder berdasarkan apa yang sebenarnya akan diinjeksikan server.

Catatan kompatibilitas

  • Jangan menggunakan ulang placeholder di antara pengenal dan string. Sebuah reserved name seperti __TOKEN__ dan sebuah reserved string yang mencocokkan __TOKEN__ menggambarkan dua jalur kode yang berbeda (larik reserved-expressions vs. larik reserved-strings). Gunakan bentuk tekstual yang berbeda untuk masing-masing - misalnya, konvensi UPPER_SNAKE untuk placeholder pengenal dan bentuk yang dibungkus delimiter ({{ ... }}, %{...}, <<<...>>>) untuk placeholder string. Dengan begitu, bug pada satu regex tidak dapat diam-diam mencocokkan yang lainnya.
  • Regex reservedStrings dijalankan terhadap nilai string mentah. Regex dicocokkan terhadap nilai runtime dari string tersebut, bukan teks sumbernya. \{\{[^}]+\}\} mencocokkan string yang mengandung {{.something}} (atau bentuk {{...}} lainnya). Jika placeholder Anda mungkin dibungkus konten tambahan ("prefix-{{.Field}}-suffix"), regex tersebut tetap cocok tetapi seluruh string dipertahankan - rencanakan substitusi Anda sesuai dengan itu.
  • Berfungsi dengan template engine apa pun. Meskipun contohnya menggunakan sintaks Go text/template, tidak ada apa pun dalam integrasi javascript-obfuscator yang khusus Go. Apa pun yang dapat melakukan penggantian pada tingkat string terhadap keluaran obfuscator akan berfungsi: Rails ERB, Django, PHP short-tag, sed dalam pipeline CI, dan sebagainya. Pilih delimiter yang dikeluarkan engine Anda secara alami dan yang tidak bertabrakan dengan sintaks JS nyata.