Obtener la clave del array de bytecode desde el backend
Mantén la clave de descifrado del bytecode de la VM fuera del cliente: obtenla de tu backend en el momento de la carga con un key getter asíncrono, protegido tras la autenticación para que un bundle robado quede inservible.
El problema
vmBytecodeArrayEncoding cifra el bytecode de la VM con una clave. Si esa clave se envía
dentro del bundle, cualquiera que tenga el archivo dispone de todo lo necesario para descifrarlo. Un vmBytecodeArrayEncodingKeyGetter permite
que la clave viva en otro lugar y se produzca en tiempo de ejecución, pero un getter síncrono solo puede leer lo que ya está presente
en el cliente (una global, una cookie, localStorage). Para obtener la clave de tu servidor —de modo que puedas protegerla tras
la autenticación y revocarla—, el getter tiene que ser asíncrono.
La solución
Activa vmAsyncExecutor (v7.3.0+). Con el ejecutor asíncrono, el key getter puede
devolver una Promise, de modo que puede hacer fetch de la clave desde tu backend antes de que se ejecute la VM. Tres opciones trabajan juntas:
vmBytecodeArrayEncoding: true— cifra el array de bytecode.vmBytecodeArrayEncodingKey— la clave usada en tiempo de compilación (guardada en tu servidor, no en el bundle).vmBytecodeArrayEncodingKeyGetter— una expresión JS que devuelve esa misma clave en tiempo de ejecución. ConvmAsyncExecutoractivada puede devolver unaPromise; sin él, el getter debe devolver la clave de forma síncrona.
Configuración de ofuscación del cliente
JavaScriptObfuscator.obfuscate(sourceCode, {
vmObfuscation: true,
vmAsyncExecutor: true,
vmBytecodeArrayEncoding: true,
vmBytecodeArrayEncodingKey: process.env.VM_KEY, // e.g. 'mySecretKey123'
vmBytecodeArrayEncodingKeyGetter:
'fetch("/api/vm-key", { credentials: "include" }).then((res) => res.text())'
});
La expresión del getter se incrusta literalmente y se evalúa en el navegador. Mantén la clave de tiempo de compilación
vmBytecodeArrayEncodingKey fuera del repositorio de tu cliente: inyéctala desde una variable de entorno o un secreto en el momento del build,
y sirve exactamente la misma cadena desde el endpoint de abajo.
Cómo funcionan las dos claves
Tu clave nunca se usa por sí sola: en ambos lados se mezcla con una clave interna que el ofuscador controla:
- En tiempo de compilación.
vmBytecodeArrayEncodingKeyse combina con una clave interna que el ofuscador deriva, y el array de bytecode se codifica con la clave mezclada resultante. - En tiempo de ejecución. El valor al que se resuelve tu
vmBytecodeArrayEncodingKeyGetter—devuelto por tu servidor— se combina con la misma clave interna, reconstruida en el cliente a partir de varios factores del entorno de ejecución, para decodificar el bytecode.
Como ambos lados mezclan tu clave con la clave interna, el getter debe resolverse a la misma cadena exacta que pasaste
como vmBytecodeArrayEncodingKey. Ninguna de las piezas es suficiente por sí sola: tu clave sin la clave interna no puede decodificar el
bytecode, y la clave interna es inútil sin la tuya, motivo por el cual servir tu clave solo a quienes están autenticados
mantiene un bundle robado inservible.
Lado del servidor
El endpoint decide qué clave devolver en función de lo que tu aplicación considere de confianza: una sesión válida, un
Origin o Referer esperado, una comprobación de licencia, etc. El truco: en lugar de rechazar a quienes no son de confianza, devuelve una
clave incorrecta. El bytecode se decodifica entonces a basura y el código protegido falla por sí solo, lo cual es más sigiloso que un
401 evidente que le dice al atacante exactamente qué debe eludir.
// Express example — the exact checks depend on your app
app.get('/api/vm-key', (req, res) => {
const origin = req.get('origin');
const trusted =
req.session?.user && // a valid session, and
origin === 'https://app.example.com'; // the expected production origin
res.type('text/plain').send(
// Real key for valid users; a decoy for everyone else
// (no session, or a localhost / unexpected origin).
trusted ? process.env.VM_KEY : process.env.VM_DECOY_KEY
);
});
