Telemetria e reações das defesas da VM
Reporte as detecções das defesas da VM ao seu backend com vmDefenseHook e ajuste como cada categoria de detecção reage com vmDefenseReaction - de um build totalmente não destrutivo, apenas de telemetria, a quebrar de forma severa em um bundle roubado.
O problema
As defesas da VM - vmSelfDefending, vmDebugProtection e vmDomainLock - agem localmente: quando um depurador, ferramenta de automação, ambiente adulterado ou domínio não autorizado é detectado, o código protegido quebra ou silenciosamente envenena seus próprios resultados. Isso detém o atacante, mas, por padrão, você nunca fica sabendo. Você não tem como saber com que frequência seu bundle está sendo sondado, qual detector disparou ou se uma defesa está quebrando para um usuário legítimo.
Desde a v7.1.0, duas opções fecham essa lacuna. Nenhuma delas ativa qualquer defesa - elas apenas observam e orientam as defesas que você já ativou:
vmDefenseHook- um callback global que recebe um objeto de sinal toda vez que uma defesa detecta algo. Use-o para enviar telemetria ao seu backend.vmDefenseReaction- um mapa por categoria que seleciona como uma defesa ativada reage: quebrar, envenenar ou não fazer nada localmente.
Receita 1 - reportar detecções ao seu backend
Passo 1 - registre uma função de hook global, antes que o bundle ofuscado carregue
O runtime da VM e suas defesas rodam antes do seu programa protegido, então muitas detecções disparam durante a inicialização. Defina o hook como um global simples na página host, antes da tag de script ofuscada:
<script>
// In your page, BEFORE the obfuscated script:
window.__vmDetection = function (signal) {
navigator.sendBeacon('/api/vm-defense', JSON.stringify(signal));
};
</script>
<script src="/app.obfuscated.js"></script>
Passo 2 - aponte vmDefenseHook para ela
A opção é um objeto cujo name é a função global a ser chamada (aliases é opcional - veja abaixo):
JavaScriptObfuscator.obfuscate(source, {
vmObfuscation: true,
// the hook alone enables nothing - a defense must be on for detectors to run:
vmSelfDefending: true,
vmDebugProtection: true,
vmDefenseHook: { name: '__vmDetection' }
});
A forma de string simples (vmDefenseHook: '__vmDetection') ainda é aceita como abreviação de { name: '__vmDetection' }, mas está obsoleta - prefira a forma de objeto.
No painel, o campo VM Defense Hook aparece no painel de opções da VM assim que pelo menos uma defesa (vmSelfDefending, vmDebugProtection ou vmDomainLock) está ativada.
Passo 3 - receba o sinal no seu backend
Toda detecção chama o hook com um único objeto signal:
source- o detector específico:headless,node,agent,domain,debugger,sandbox,nativeHook,timingouintegrity. A partir da v7.4.0, os antigos detectoresenveinspectorreportam sobsource: 'debugger'.category-automation,debugger,sandbox,domain,tamperouintegrity. A origemnodereporta sobcategory: 'debugger'(v7.4.0+).score,threshold- a pontuação da detecção e o limiar que ela cruzou
Um endpoint de recebimento mínimo (mostrado com Express; qualquer backend que aceite um POST funciona). Ele normaliza o corpo para um array, então também lida com a forma em lote enviada pelo padrão de buffer abaixo:
app.post('/api/vm-defense', express.text({ type: '*/*' }), (req, res) => {
// a signal: { source: 'headless', category: 'automation', score: 7, threshold: 4 }
const signals = [].concat(JSON.parse(req.body));
for (const signal of signals) {
console.warn('vm-defense', { ...signal, ip: req.ip, ua: req.get('user-agent') });
}
res.sendStatus(204);
});
Renomeando os campos do sinal (aliases) v7.4.0+
Os valores padrão de source / category são nomes descritivos, então qualquer pessoa que instrumente o callback (ou leia a saída) pode reconhecer a proteção e qual detector disparou. aliases renomeia os campos do sinal para tokens opacos de sua escolha, aplicados dentro da VM antes de o sinal ser emitido, de modo que esses nomes nunca aparecem na saída nem chegam ao callback. Seu app conhece o próprio mapeamento e encaminha os tokens ao seu backend.
Os aliases são por campo: cada um recebe uma key (o nome da propriedade que o callback recebe); os campos de nome do tipo string source e category também recebem um mapa values, enquanto score / threshold são números e recebem apenas uma key. Entradas não definidas mantêm seus nomes padrão.
vmDefenseHook: {
name: '__vmDetection',
aliases: {
source: { key: 'a8Qm', values: { headless: 'xP4m9Q' } },
category: { key: 'p3Tx', values: { automation: 'bQ7s1M' } },
score: { key: 's1' },
threshold: { key: 't1' }
}
// the callback now receives e.g. { a8Qm: 'xP4m9Q', p3Tx: 'bQ7s1M', s1: <score>, t1: <threshold> }
}
No painel, a seção Aliases de sinal fica abaixo do campo VM Defense Hook.
Receita 2 - ajustar as reações padrão
vmDefenseReaction configura como cada categoria de detecção reage. Ela não ativa nada - as próprias defesas são ligadas por vmSelfDefending, vmDebugProtection e vmDomainLock; esta opção apenas seleciona como uma defesa ativada reage. A categoria é a unidade de controle: todo detector de uma categoria aplica a reação daquela categoria, e uma reação definida para uma categoria cuja opção está desligada simplesmente não tem efeito.
| Categoria | Ativada por | Reage quando |
|---|---|---|
automation | vmSelfDefending ou vmDebugProtection | O código está sendo controlado por software em vez de uma pessoa: um navegador headless ou automatizado, um framework de scraping / testes ou um agente de código de IA percorrendo a página. |
debugger | vmDebugProtection ou vmSelfDefending | Alguém tem um depurador ou o inspetor de ferramentas de desenvolvedor do navegador aberto e está percorrendo o código em execução para entendê-lo. |
sandbox | vmDebugProtection | O código não está rodando em um navegador real - ele foi transportado para um ambiente JavaScript emulado ou controlado por script para ser executado e estudado offline. |
domain | vmDomainLock | O código está rodando em um site que você não autorizou: um host que não está na sua lista de permissões vmDomainLock (por exemplo, seu bundle copiado para o domínio de outra pessoa). |
tamper | vmSelfDefending | O ambiente JavaScript ao redor da VM foi modificado para observá-la ou sequestrá-la, como funções nativas do navegador substituídas por versões instrumentadas. |
integrity | vmSelfDefending | O próprio código do bundle protegido foi editado ou modificado desde que você o gerou. |
As chaves são esses seis nomes de categoria, ou default (um fallback para categorias não especificadas). Os valores são:
break- quebra imediatamentedecoy- continua rodando em estado envenenado, produzindo silenciosamente resultados erradosnone- não faz nada localmente (apenas telemetria)
Uma categoria que você não define recai sobre os padrões internos:
// built-in defaults
vmDefenseReaction: {
automation: 'break',
debugger: 'decoy',
sandbox: 'decoy',
domain: 'break',
tamper: 'break',
integrity: 'break'
}
default alcança todas as categorias, incluindo as corretas por construção (integrity, tamper), então { default: 'none' } é um build genuinamente não destrutivo, apenas de telemetria:
vmDefenseReaction: { default: 'none' } // never break - pair with vmDefenseHook
vmDefenseReaction: { automation: 'none' } // tolerate automation FPs; the rest keep their defaults (a bad domain still breaks)
No painel, os seletores VM Defense Reactions aparecem no painel de opções da VM assim que uma defesa é ativada; cada categoria só é editável enquanto uma defesa que emite seus detectores estiver ligada.
Da telemetria à aplicação
Você não precisa escolher entre visibilidade e aplicação logo no primeiro dia. Implante as defesas em dois builds: um que apenas reporta e, depois - quando a telemetria estiver limpa -, um que reage.
Passo 1 - publique um build somente de observação
Ative todas as defesas que você pretende usar, aponte vmDefenseHook para o seu endpoint e desligue todas as reações. Cada detector ainda roda e reporta cada ocorrência ao seu backend - ele apenas nunca quebra nada:
JavaScriptObfuscator.obfuscate(source, {
vmObfuscation: true,
vmSelfDefending: true,
vmDebugProtection: true,
vmDomainLock: ['example.com'],
vmDefenseHook: '__vmDetection',
vmDefenseReaction: { default: 'none' } // observe only
});
Passo 2 - revise os sinais coletados
Depois que o build receber tráfego real, procure detecções que o uso legítimo disparou. As duas mais comuns:
- ocorrências de
automationvindas dos seus próprios testes end-to-end ou do monitoramento de disponibilidade - construa esses artefatos sem as defesas em vez de tolerar a categoria em produção. - ocorrências de
domainvindas de um host de staging ou preview que você esqueceu de incluir na lista de permissõesvmDomainLock- adicione o host.
Prefira corrigir a causa a suavizar uma reação: cada categoria deixada em none é um detector com o qual um atacante não precisa mais se preocupar.
Passo 3 - ative as reações
Remova a substituição default: 'none' para que as reações internas por categoria sejam aplicadas - toda a mudança é essa única linha. Se uma categoria continuar produzindo falsos positivos que você não consegue eliminar, mantenha apenas essa categoria em none (por exemplo, vmDefenseReaction: { automation: 'none' }) e aplique o restante.
