Substituição de templates no servidor
Injete valores renderizados pelo servidor (por exemplo, placeholders `{{ .Field }}` no estilo de template do Go) em JavaScript ofuscado por VM sem quebrar o pipeline de ofuscação.
O problema
O seu backend (Go, Rails, Django, PHP, …) serve um arquivo JavaScript cujo conteúdo precisa ser parcialmente renderizado
a cada requisição - um endpoint de API, uma lista de feature flags, um blob de estado inicial, um id de build, um nonce. Você ofusca o
JS com vmObfuscation: true, mas também precisa que o template engine substitua placeholders na saída ofuscada
depois que a ofuscação termina. reservedNames e reservedStrings mantêm um placeholder visível na saída
para que ele possa ser substituído. Sem eles, um placeholder de string é absorvido pelo bytecode da VM e um placeholder de identificador
é emitido em vários pontos reescritos, então o template engine ou não encontra nada para substituir ou quebra a saída.
Considere carregar os valores como dados
Se puder, evite completamente editar a saída protegida: carregue a configuração de execução como dados antes de o bundle protegido
rodar. Mantenha-a em um script separado ou obtenha-a de um endpoint autenticado. Isso preserva a saída protegida, de modo que
vmSelfDefending pode continuar ativado. Dados entregues a um navegador ficam visíveis para esse navegador de qualquer forma.
Use os padrões abaixo quando os valores realmente precisarem ser substituídos dentro do arquivo ofuscado.
Uma observação sobre os exemplos em Go: eles fazem uma substituição simples de string (strings.ReplaceAll / strings.NewReplacer) na
saída ofuscada e cuidam do próprio escape, mostrado em cada padrão. Eles não passam pelo pacote html/template do Go -
isso aplicaria por cima o escape contextual de JavaScript do próprio pacote, escapando o payload duas vezes. Se você renderizar
pelo html/template, remova o escape manual e deixe o engine escapar uma única vez.
Qual opção escolher?
| O valor do servidor é… | Use |
|---|---|
| Um valor JS bruto (array, objeto, número, booleano - qualquer valor JSON) | Padrão 1 - reservedNames + placeholder de identificador |
| Uma string (o caso comum - JSON renderizado, um id de build, um nonce) | Padrão 2 - reservedStrings + placeholder em template literal |
| Uma string, quando o código precisa continuar ES5 ou a API ao redor exige um literal de string entre aspas | Padrão 3 - reservedStrings + placeholder em string entre aspas |
A substituição após a ofuscação é incompatível com vmSelfDefending: true. Veja as
Notas de compatibilidade no fim desta receita.
Padrão 1 - reservedNames com um placeholder de identificador
Ideal para: injetar expressões JS brutas (arrays, objetos, números, …) sem nenhuma preocupação com escape de aspas.
Escolha um identificador característico que nunca vá colidir com o código real, referencie-o diretamente e liste em reservedNames uma regex
que corresponda a ele. Na ofuscação VM, o identificador passa pelo array de expressões reservadas e
aparece literalmente na saída, por exemplo:
Substitua o identificador por uma expressão completa serializada em JSON. Não cole o valor dentro de aspas ou crases -
o identificador não está dentro de um literal de string, então o valor injetado é interpretado pelo motor JS como uma expressão
comum. Use um serializador confiável, escape < quando o script estiver embutido em HTML e teste valores que contenham
aspas, barras invertidas, quebras de linha, crases e ${...}.
Padrão 2 - reservedStrings com um placeholder em template literal
Ideal para: template engines no estilo Go / Jinja que exigem delimitadores como {{ .Field }}, que por acaso são texto JS
válido quando envolvidos em crases.
O placeholder fica dentro de um template literal com um único quasi e sem interpolação. Na ofuscação VM, ele passa pelo array de expressões reservadas, o que preserva a forma original com crases na saída.
Código-fonte
Opções do ofuscador
Interface
Para reservar o placeholder {{.Config.FeatureFlags}} do código-fonte acima, adicione esta regex ao campo Reserved Strings -
com barras invertidas simples. A interface armazena o valor literalmente, então, ao contrário do código JS, as barras invertidas não são
duplicadas:

API
Após a ofuscação
O placeholder é preservado byte a byte, incluindo as crases ao redor.
Substituição no servidor
Substitua {{.Config.FeatureFlags}} por uma string JSON escapada para um template literal. Crases não exigem escapar
as " internas, mas uma barra invertida, uma crase ou ${ dentro do payload ainda mudariam ou encerrariam o literal, então escape
esses três:
Em tempo de execução: JSON.parse(`{"newCheckout":true,"darkMode":false}`) - funciona.
Por que preferir template literals a aspas simples/duplas para valores de string? Crases não exigem escapar "
dentro do payload JSON. Isso importa porque a maioria dos valores renderizados pelo servidor é JSON, e JSON é cheio de aspas
duplas. Com um placeholder entre aspas duplas, você precisaria escapar cada " interna (veja o Padrão 3); com crases,
o payload só precisa ter escapadas as raras barras invertidas, crases e ${.
Padrão 3 - reservedStrings com um placeholder em string entre aspas
Ideal para: código-fonte que precisa continuar em ES5 (sem template literals) ou casos em que a API ao redor espera um literal de string comum.
O placeholder é um literal de string entre aspas simples ou duplas. Na ofuscação VM, ele passa pelo
array de strings reservadas, que é emitido como um array JS serializado com JSON.stringify - sempre com aspas duplas, independentemente
do estilo de aspas da entrada.
Código-fonte
Opções do ofuscador
Interface
Para reservar o placeholder {{.Page.Tags}} do código-fonte acima, adicione esta regex ao campo Reserved Strings -
com barras invertidas simples. A interface armazena o valor literalmente, então, ao contrário do código JS, as barras invertidas não são duplicadas:

API
Após a ofuscação
Substituição no servidor
Como o placeholder fica dentro de uma string JS entre aspas duplas, o payload JSON injetado precisa ter as barras invertidas e
os caracteres " internos escapados:
Saída resultante:
Em tempo de execução: JSON.parse("[\"news\",\"tech\",\"release\"]") → ["news","tech","release"].
Se você esquecer o escape, o navegador vai ver aspas desbalanceadas e lançar um SyntaxError. O Padrão 2 evita
totalmente as aspas duplas usando crases.
Vários placeholders em um mesmo programa
Os três padrões podem ser combinados. Uma única regex de reservedStrings com uma alternância pode corresponder a todos os formatos de placeholder que o seu
template engine emite - aqui, tanto no estilo {{ .Field }} quanto no estilo %{ .Field }:
Você pode misturar placeholders de identificador (para valores JS brutos) e placeholders de string (para JSON renderizado) no mesmo código-fonte - escolha para cada placeholder com base no que o servidor vai realmente injetar.
Notas de compatibilidade
vmSelfDefending quebra a substituição após a ofuscação
O VM Self Defending detecta qualquer alteração na saída ofuscada depois do build, inclusive uma substituição legítima de template, e o código protegido então se recusa a rodar.
Se você depende da substituição de templates no servidor, defina vmSelfDefending: false. Deixe selfDefending desativado também: ele
não tem efeito na ofuscação VM e, sem a VM, também proíbe qualquer alteração na saída.
Dicas sobre placeholders
- Não reutilize placeholders entre identificadores e strings. Um nome reservado como
__TOKEN__e uma string reservada que corresponde a__TOKEN__descrevem dois caminhos de código diferentes (array de expressões reservadas vs. array de strings reservadas). Use formatos textuais distintos para cada um - por exemplo, uma convençãoUPPER_SNAKEpara placeholders de identificador e um formato envolvido por delimitadores ({{ ... }},%{...},<<<...>>>) para placeholders de string. Assim, um bug em uma regex não pode corresponder silenciosamente à outra. - As regexes de
reservedStringsrodam sobre os valores brutos das strings. A regex é comparada com o valor da string em tempo de execução, não com o texto do código-fonte.\{\{[^}]+\}\}corresponde a strings que contêm{{.something}}(ou qualquer outro formato{{...}}). Se o seu placeholder puder estar envolvido em conteúdo extra ("prefix-{{.Field}}-suffix"), a regex ainda corresponde, mas a string inteira é preservada - planeje a substituição de acordo. - Funciona com qualquer template engine. Embora os exemplos usem a sintaxe do Go, nada na integração com o javascript-obfuscator é específico do Go. Qualquer coisa capaz de fazer uma substituição em nível de string na saída do ofuscador funciona: Rails ERB, Django, short tags do PHP, sed em um pipeline de CI etc. Escolha delimitadores que o seu engine emita naturalmente e que não colidam com a sintaxe JS real.
