Documentation
/
Recettes
/

Récupérer la clé du tableau de bytecode depuis le backend

Récupérer la clé du tableau de bytecode depuis le backend

Pro
v7.3.0+

Gardez la clé de déchiffrement du bytecode VM hors du client : récupérez-la depuis votre backend au chargement grâce à un getter de clé asynchrone, protégé par authentification, afin qu'un bundle dérobé reste inerte.

Le problème

vmBytecodeArrayEncoding chiffre le bytecode de la VM avec une clé. Si cette clé est livrée dans le bundle, quiconque possède le fichier dispose de tout ce qu'il faut pour le déchiffrer. Un vmBytecodeArrayEncodingKeyGetter permet à la clé de résider ailleurs et d'être produite à l'exécution — mais un getter synchrone ne peut lire que ce qui est déjà présent sur le client (une globale, un cookie, localStorage). Pour récupérer la clé depuis votre serveur — et donc la protéger derrière une authentification et pouvoir la révoquer — le getter doit être asynchrone.

La solution

Activez vmAsyncExecutor (v7.3.0+). Avec l'exécuteur asynchrone, le getter de clé peut renvoyer une Promise : il peut donc récupérer (fetch) la clé depuis votre backend avant l'exécution de la VM. Trois options se combinent :

  • vmBytecodeArrayEncoding: true — chiffre le tableau de bytecode.
  • vmBytecodeArrayEncodingKey — la clé utilisée à la compilation (conservée sur votre serveur, jamais dans le bundle).
  • vmBytecodeArrayEncodingKeyGetter — une expression JS renvoyant cette même clé à l'exécution. Avec vmAsyncExecutor activé, elle peut renvoyer une Promise ; sans lui, le getter doit renvoyer la clé de façon synchrone.

Configuration d'obfuscation côté client

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

L'expression du getter est intégrée telle quelle et évaluée dans le navigateur. Gardez la clé de compilation vmBytecodeArrayEncodingKey hors de votre dépôt client — injectez-la depuis une variable d'environnement ou un secret au moment du build, et servez exactement la même chaîne depuis le point de terminaison décrit ci-dessous.

Comment les deux clés fonctionnent

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

  • À 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 obtenue.
  • À l'exécution. La valeur résolue par votre vmBytecodeArrayEncodingKeyGetter — renvoyée par votre serveur — est combinée à cette même clé interne, reconstituée côté client à partir de divers facteurs d'exécution, afin de décoder le bytecode.

Comme les deux côtés mélangent votre clé avec la clé interne, le getter doit résoudre vers exactement la même chaîne que celle passée à vmBytecodeArrayEncodingKey. Aucun des deux éléments ne suffit à lui seul : votre clé sans la clé interne ne permet pas de décoder le bytecode, et la clé interne ne sert à rien sans la vôtre — c'est bien pour cela que ne servir votre clé qu'à des appelants authentifiés maintient un bundle dérobé à l'état inerte.

Côté serveur

Le point de terminaison décide quelle clé renvoyer selon les critères auxquels votre application fait confiance — une session valide, un en-tête Origin ou Referer attendu, une vérification de licence, etc. L'astuce : au lieu de rejeter les appelants non fiables, renvoyez une mauvaise clé. Le bytecode se décode alors en données inexploitables et le code protégé échoue de lui-même, ce qui est plus discret qu'un 401 explicite qui indiquerait à un attaquant exactement quoi 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
    );
});