Documentation
/
Recettes
/

Clé d'encodage du tableau de bytecode

Externaliser la clé de chiffrement du tableau de bytecode

Pro

Fournissez votre propre clé de chiffrement du bytecode de la VM avec vmBytecodeArrayEncodingKey et restituez-la à l'exécution via un getter de clé — conservée hors du bundle, lue depuis le stockage client ou récupérée depuis votre backend.

Ce que font ces options

vmBytecodeArrayEncoding chiffre le tableau de bytecode de la VM afin qu'il ne figure pas en clair dans la sortie. Par défaut, la clé de chiffrement est dérivée de l'environnement et reconstruite sur le client, de sorte que vous n'avez jamais à la manipuler. C'est pratique, mais le matériel de clé réside toujours dans le bundle.

Deux options vous permettent de sortir la clé du bundle et de la contrôler vous-même :

  • vmBytecodeArrayEncodingKey — la clé que vous fournissez à la compilation. Lorsqu'elle est définie, elle est utilisée à la place de la clé par défaut dérivée de l'environnement, et elle n'est pas intégrée à la sortie obfusquée.
  • vmBytecodeArrayEncodingKeyGetter — une expression JavaScript qui renvoie cette même clé à l'exécution. Elle est intégrée telle quelle et évaluée dans le navigateur au chargement du code obfusqué.

L'intérêt réside dans la séparation : comme la clé ne figure pas dans le code, une analyse purement statique du bundle ne peut pas la récupérer. Elle doit tout de même être présente à l'exécution pour que le code fonctionne, elle n'est donc pas véritablement secrète — mais vous décidez d'où elle provient et qui peut la voir.

Comment les deux clés se combinent

Votre clé n'est jamais utilisée seule — des deux côtés, elle est mélangée à une clé interne que l'obfuscateur contrôle :

  • À la compilation. vmBytecodeArrayEncodingKey est combinée à une clé interne dérivée par l'obfuscateur, et le tableau de bytecode est encodé avec la clé mixte résultante.
  • À l'exécution. La valeur à laquelle se résout votre vmBytecodeArrayEncodingKeyGetter est combinée à la même clé interne, reconstruite sur le client à partir de divers facteurs d'exécution, pour décoder le bytecode.

Comme les deux côtés mélangent votre clé à la clé interne, le getter doit se résoudre à exactement la même chaîne que celle que vous avez passée en tant que vmBytecodeArrayEncodingKey. Aucune des deux parties ne suffit à elle seule : votre clé sans la clé interne ne peut pas décoder le bytecode, et la clé interne est inutile sans la vôtre — c'est pourquoi contrôler qui reçoit votre clé est ce qui protège réellement le code.

Fournir la clé à l'exécution

Par défaut, le getter est synchrone : l'expression doit renvoyer la clé immédiatement au chargement du code obfusqué. Lisez-la depuis n'importe quelle source déjà présente sur le client — un cookie, localStorage, une variable globale ou un élément du DOM injecté par le serveur.

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 clé doit exister avant l'exécution du code obfusqué :

// Set by a different script, a server-injected inline script, etc.
window.__VM_KEY__ = 'mySecretKey123';

D'autres sources synchrones fonctionnent de la même manière — choisissez celle que votre application renseigne déjà :

// 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"

Récupérer la clé depuis votre backend (async)

Requiert vmAsyncExecutor · v7.3.0+

Un getter synchrone ne peut lire que ce qui se trouve déjà sur le client. Pour récupérer la clé depuis votre serveur — afin de pouvoir la protéger derrière une authentification et la révoquer —, le getter doit être asynchrone, ce qui requiert vmAsyncExecutor. Lorsque l'exécuteur asynchrone est activé, le getter peut renvoyer une Promise, et la VM l'attend avant de s'exécuter.

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())'
});

Sur le serveur, décidez quelle clé renvoyer en fonction de ce à quoi votre application fait confiance — une session valide, un Origin ou un Referer attendu, une vérification de licence, et ainsi de suite. L'astuce : au lieu de rejeter les appelants non fiables, renvoyez une mauvaise clé. Le bytecode se décode alors en données inutilisables et le code protégé échoue de lui-même, ce qui est plus discret qu'un 401 évident qui indique à un attaquant exactement ce qu'il doit contourner.

// 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
    );
});

Servez depuis ce point de terminaison exactement la même chaîne que celle que vous avez passée en tant que vmBytecodeArrayEncodingKey lors du build. Une copie du bundle exécutée en dehors de votre environnement reçoit la clé leurre, se déchiffre en rien du tout et reste inerte.

Lorsque la clé ne correspond pas

Le code obfusqué ne fonctionne que lorsque le getter renvoie exactement la même clé que celle utilisée lors de l'obfuscation. Si les clés diffèrent — ou si le getter renvoie undefined, null ou une chaîne vide —, le déchiffrement produit un mauvais flux de clé et le code échoue à l'exécution avec une sortie inutilisable ou une erreur d'exécution ordinaire.

Il n'existe volontairement aucun message d'erreur distinct et propre à la clé : une clé défaillante est indiscernable de toute autre défaillance à l'exécution. Ainsi, lorsqu'un bundle protégé par la VM ne lève une erreur qu'une fois cette option en jeu, vérifiez d'abord le chemin de la clé — que le getter se résout sur la page, renvoie une chaîne non vide et renvoie la même valeur que celle avec laquelle vous avez compilé.