Externalizar la clave de cifrado del array de bytecode
Proporcione su propia clave de cifrado del bytecode de la VM con vmBytecodeArrayEncodingKey y devuélvala en tiempo de ejecución mediante un getter de clave — mantenida fuera del bundle, leída desde el almacenamiento del cliente o recuperada desde su backend.
Qué hacen estas opciones
vmBytecodeArrayEncoding cifra el array de bytecode de la VM para que no aparezca
como texto plano en la salida. De forma predeterminada, la clave de cifrado se deriva del entorno y se reconstruye en el
cliente, por lo que usted nunca la manipula. Esto es cómodo, pero el material de la clave sigue residiendo en el bundle.
Dos opciones le permiten sacar la clave del bundle y controlarla usted mismo:
vmBytecodeArrayEncodingKey— la clave que usted proporciona en tiempo de compilación. Cuando se define, se utiliza en lugar de la clave predeterminada derivada del entorno, y no se incrusta en la salida ofuscada.vmBytecodeArrayEncodingKeyGetter— una expresión de JavaScript que devuelve esa misma clave en tiempo de ejecución. Se incrusta literalmente y se evalúa en el navegador cuando se carga el código ofuscado.
La clave está en la separación: como la clave no está en el código, un análisis puramente estático del bundle no puede recuperarla. Aun así debe estar presente en tiempo de ejecución para que el código funcione, por lo que no es verdaderamente secreta — pero usted decide de dónde proviene y quién puede verla.
Cómo se combinan las dos claves
Su clave nunca se utiliza por sí sola — en ambos lados se mezcla con una clave interna que controla el ofuscador:
- Tiempo de compilación.
vmBytecodeArrayEncodingKeyse combina con una clave interna que deriva el ofuscador, y el array de bytecode se codifica con la clave mixta resultante. - Tiempo de ejecución. El valor al que se resuelve su
vmBytecodeArrayEncodingKeyGetterse combina con la misma clave interna, reconstruida en el cliente a partir de diversos factores de ejecución, para decodificar el bytecode.
Como ambos lados mezclan su clave con la clave interna, el getter debe resolverse a exactamente la misma cadena que
pasó como vmBytecodeArrayEncodingKey. Ninguna de las dos partes basta por sí sola: su clave sin la clave interna no
puede decodificar el bytecode, y la clave interna es inútil sin la suya — por eso controlar quién recibe su clave es lo
que realmente protege el código.
Proporcionar la clave en tiempo de ejecución
De forma predeterminada, el getter es síncrono: la expresión debe devolver la clave de inmediato cuando se carga el
código ofuscado. Léala desde cualquier fuente que ya esté presente en el cliente — una cookie, localStorage, una
variable global o un elemento del DOM inyectado por el servidor.
JavaScriptObfuscator.obfuscate(sourceCode, {
vmObfuscation: true,
vmBytecodeArrayEncoding: true,
vmBytecodeArrayEncodingKey: process.env.VM_KEY, // e.g. 'mySecretKey123'
vmBytecodeArrayEncodingKeyGetter: "window.__VM_KEY__" // returns the key at runtime
});
La clave debe existir antes de que se ejecute el código ofuscado:
// Set by a different script, a server-injected inline script, etc.
window.__VM_KEY__ = 'mySecretKey123';
Otras fuentes síncronas funcionan de la misma manera — elija la que su aplicación ya rellene:
// From a cookie
vmBytecodeArrayEncodingKeyGetter: "document.cookie.match(/vmKey=([^;]+)/)?.[1]"
// From localStorage
vmBytecodeArrayEncodingKeyGetter: "localStorage.getItem('vmKey')"
// From a server-injected meta tag
vmBytecodeArrayEncodingKeyGetter: "document.querySelector('meta[name=\"vm-key\"]').content"
// From a nested object
vmBytecodeArrayEncodingKeyGetter: "window.config.encryption.key"
Recuperar la clave desde su backend (async)
Requiere vmAsyncExecutor · v7.3.0+Un getter síncrono solo puede leer lo que ya está en el cliente. Para recuperar la clave desde su servidor — de modo
que pueda protegerla tras una autenticación y revocarla —, el getter debe ser asíncrono, y eso requiere
vmAsyncExecutor. Con el ejecutor asíncrono habilitado, el getter puede devolver
una Promise, y la VM la espera antes de ejecutarse.
JavaScriptObfuscator.obfuscate(sourceCode, {
vmObfuscation: true,
vmAsyncExecutor: true,
vmBytecodeArrayEncoding: true,
vmBytecodeArrayEncodingKey: process.env.VM_KEY, // kept on your server, not in the bundle
vmBytecodeArrayEncodingKeyGetter:
'fetch("/api/vm-key", { credentials: "include" }).then((res) => res.text())'
});
En el servidor, decida qué clave devolver en función de aquello en lo que su aplicación confíe — una sesión válida, un
Origin o Referer esperado, una comprobación de licencia, etc. El truco: en lugar de rechazar a los llamadores no
confiables, devuelva una clave incorrecta. El bytecode se decodifica entonces en datos basura y el código protegido
falla por sí solo, lo cual es más sigiloso que un 401 evidente que le indica a un 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
);
});
Sirva desde este endpoint exactamente la misma cadena que pasó como vmBytecodeArrayEncodingKey en tiempo de
compilación. Una copia del bundle que se ejecute fuera de su entorno recibe la clave señuelo, se descifra en nada y
queda inerte.
Cuando la clave no coincide
El código ofuscado solo funciona cuando el getter devuelve exactamente la misma clave utilizada durante la
ofuscación. Si las claves difieren — o si el getter devuelve undefined, null o una cadena vacía —, el descifrado
produce un flujo de claves incorrecto y el código falla en tiempo de ejecución con una salida basura o un error de
ejecución ordinario.
Deliberadamente no existe un mensaje de error propio y específico de la clave: una clave fallida es indistinguible de cualquier otro fallo en tiempo de ejecución. Por eso, cuando un bundle protegido por la VM lanza un error solo una vez que esta opción entra en juego, compruebe primero la ruta de la clave — que el getter se resuelve en la página, devuelve una cadena no vacía y devuelve el mismo valor con el que compiló.
