Dokümantasyon
/
Tarifler
/

Sunucu Tarafında Şablon Değişimi

Host-side Template Substitution

v6.10.0+

Sunucu tarafından oluşturulan değerleri (örneğin Go html/template `{{ .Field }}` ifadeleri) obfuscation işlem hattını bozmadan VM ile obfuscate edilmiş JavaScript'e enjekte edin.

Sorun

Backend'iniz (Go, Rails, Django, PHP, …), içeriği istek başına kısmen oluşturulması gereken bir JavaScript dosyası sunar

  • bir API uç noktası, bir özellik bayrakları listesi, bir başlangıç durumu blob'u, bir derleme kimliği, bir nonce. JS'i vmObfuscation: true ile obfuscate edersiniz, ancak aynı zamanda şablon motorunun, obfuscation bittikten sonra obfuscate edilmiş çıktıdaki yer tutucuları değiştirmesi gerekir. Yer tutucular VM bayt koduna (dizeler ve tanımlayıcılar için varsayılan) dahil edilirse, şablon motorunun değiştirecek bir şeyi kalmaz.

Hangi seçeneği seçmeliyim?

Sunucu değeri…Kullanın
Bir ham JS ifadesi (dizi değişmezi, nesne, sayı, boolean, fonksiyon çağrısı)reservedNames + tanımlayıcı yer tutucu
Bir string ve şablon sınırlayıcılarını siz kontrol ediyorsunuzreservedStrings + şablon değişmezi yer tutucu
Bir string ve şablon motoru belirli sınırlayıcıları zorunlu kılıyor (örneğin Go {{ .Field }})reservedStrings + string veya şablon değişmezi yer tutucu

Kalıp 1 - tanımlayıcı yer tutucu ile reservedNames

En uygun: sıfır tırnak kaçışı endişesiyle ham JS ifadeleri (diziler, nesneler, sayılar, …) enjekte etmek.

Gerçek kodla asla çakışmayacak ayırt edici bir tanımlayıcı seçin, ona doğrudan başvurun ve reservedNames içinde onunla eşleşen bir regex listeleyin. VM obfuscation altında, tanımlayıcı ayrılmış-ifadeler dizisi üzerinden yönlendirilir ve çıktıda birebir görünür.

Kaynak

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

Obfuscator seçenekleri

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

Obfuscation'dan sonra

Çıktının bir yerinde şuna benzer bir ayrılmış-ifadeler dizisi bulacaksınız:

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

__INITIAL_STATE__ belirteci, tanımlayıcı yeniden adlandırmadan kurtulur ve VM bayt koduna dahil edilmez.

Sunucu tarafı değiştirme (Go örneği)

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

…burada Go şablonunuz belirteci ham bir JS ifadesiyle değiştirir:

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

Sonuç:

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

Tırnak yok, kaçış yok - enjekte edilen değer, JS motoru tarafından sıradan bir ifade olarak ayrıştırılır.

Kalıp 2 - şablon değişmezi yer tutucu ile reservedStrings

En uygun: ters tırnak içine alındığında geçerli JS metni olan {{ .Field }} gibi sınırlayıcılar gerektiren Go / Jinja tarzı şablon motorları.

Yer tutucu, tek-parçalı, değer yerleştirmesi olmayan bir şablon değişmezi içinde yaşar. VM obfuscation altında bu, ayrılmış-ifadeler dizisi üzerinden yönlendirilir ve çıktıda ham ters tırnak biçimini korur.

Kaynak

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

Obfuscator seçenekleri

Arayüz

Yukarıdaki kaynaktan {{.Config.FeatureFlags}} yer tutucusunu ayırmak için, bu regex'i Reserved Strings alanına tek ters eğik çizgilerle ekleyin. Arayüz değeri birebir saklar, bu nedenle JS kodundakinin aksine ters eğik çizgiler ikiye katlanmaz:

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

Regex'in tek ters eğik çizgilerle girildiği obfuscator arayüzündeki Reserved Strings alanı

API

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

Obfuscation'dan sonra

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

Yer tutucu, çevreleyen ters tırnaklar dahil bayt bayt korunur.

Sunucu tarafı değiştirme

{{.Config.FeatureFlags}} yerine geçerli bir JSON dizesi koyun - çalışma zamanında ters tırnaklar içinde yer alacaktır ve bunlar iç tırnak kaçışı gerektirmez:

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

Çalışma zamanında: JSON.parse(`{"newCheckout":true,"darkMode":false}`) - çalışır.

Kalıp 3 - tırnaklı string yer tutucu ile reservedStrings

En uygun: ES5'te kalması gereken (şablon değişmezi olmayan) kaynak kodu veya çevreleyen API'nin normal bir string değişmezi beklediği durumlar.

Yer tutucu, tek veya çift tırnaklı bir string değişmezidir. VM obfuscation altında, JSON.stringify ile serileştirilmiş bir JS dizisi olarak yayılan ayrılmış-dizeler dizisi üzerinden yönlendirilir - giriş tırnak stilinden bağımsız olarak her zaman çift tırnaklı.

Kaynak

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

Obfuscator seçenekleri

Arayüz

Yukarıdaki kaynaktan {{.Page.Tags}} yer tutucusunu ayırmak için, bu regex'i Reserved Strings alanına tek ters eğik çizgilerle ekleyin. Arayüz değeri birebir saklar, bu nedenle JS kodundakinin aksine ters eğik çizgiler ikiye katlanmaz:

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

Regex'in tek ters eğik çizgilerle girildiği obfuscator arayüzündeki Reserved Strings alanı

API

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

Obfuscation'dan sonra

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

Sunucu tarafı değiştirme

Yer tutucu, çift tırnaklı bir JS dizesi içinde yer aldığından, enjekte edilen JSON yükünün içteki " karakterlerinin \" ile kaçırılması gerekir:

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)

Ortaya çıkan çıktı:

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

Çalışma zamanında: JSON.parse("[\"news\",\"tech\",\"release\"]")["news","tech","release"].

Kaçışı unutursanız, tarayıcı dengesiz tırnaklar görür ve bir SyntaxError fırlatır. Kalıp 2, ters tırnak kullanarak bunu tamamen atlar.

Bir programda birden fazla yer tutucu

Üç kalıbın üçü de birlikte kullanılabilir. Bir alternasyon içeren tek bir reservedStrings regex'i, şablon motorunuzun ürettiği her yer tutucu biçimiyle eşleşebilir:

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

Aynı kaynakta tanımlayıcı yer tutucularını (ham JS değerleri için) ve string yer tutucularını (oluşturulan JSON için) karıştırabilirsiniz - sunucunun gerçekte ne enjekte edeceğine göre yer tutucu başına seçim yapın.

Uyumluluk notları

  • Yer tutucuları tanımlayıcılar ve dizeler arasında yeniden kullanmayın. __TOKEN__ gibi bir ayrılmış ad ve __TOKEN__ ile eşleşen bir ayrılmış dize, iki farklı kod yolunu tanımlar (ayrılmış-ifadeler dizisi ile ayrılmış-dizeler dizisi). Her biri için farklı metinsel biçimler kullanın - örneğin, tanımlayıcı yer tutucuları için bir UPPER_SNAKE düzeni ve string yer tutucuları için sınırlayıcıyla sarılmış bir biçim ({{ ... }}, %{...}, <<<...>>>). Böylece bir regex'teki hata, diğerini sessizce eşleştiremez.
  • reservedStrings regex'leri ham dize değerlerine karşı çalışır. Regex, kaynak metne değil, dizenin çalışma zamanı değerine karşı eşleştirilir. \{\{[^}]+\}\}, {{.something}} (veya başka herhangi bir {{...}} biçimini) içeren dizelerle eşleşir. Yer tutucunuz ekstra içerikle sarılabiliyorsa ("prefix-{{.Field}}-suffix"), regex yine de eşleşir ancak dizenin tamamı korunur - değiştirmenizi buna göre planlayın.
  • Herhangi bir şablon motoruyla çalışır. Örnekler Go text/template sözdizimini kullansa da, javascript-obfuscator entegrasyonunda Go'ya özgü hiçbir şey yoktur. Obfuscator'ın çıktısı üzerinde dize düzeyinde değiştirme yapabilen her şey işe yarar: Rails ERB, Django, PHP kısa etiketleri, bir CI işlem hattındaki sed vb. Motorunuzun doğal olarak ürettiği ve gerçek JS sözdizimiyle çakışmayan sınırlayıcılar seçin.