Externaliser la clé de Bytecode Array Encoding
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.
Regarder
Obfuscator.io Async Executor: Async Bytecode Key Getter and Async-Only VM Virtualization
Obfuscator.io Custom Bytecode Key: Compile-Time Key and Runtime Key Getter (Cookie, Fetch, Decoy Key)
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
côté client : vous n'avez donc jamais à la manipuler. C'est pratique, mais le matériel de clé reste 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 remplace la clé dérivée de l'environnement par défaut, 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 est la séparation : comme la clé ne se trouve pas dans le code, une analyse purement statique du bundle ne peut pas la retrouver. Elle doit malgré tout être présente à l'exécution pour que le code fonctionne ; elle n'est donc pas véritablement secrète, mais c'est vous qui décidez d'où elle provient et qui peut la voir.
Ces deux options vont de pair, et l'obfuscateur l'impose : définir l'une sans l'autre provoque une erreur de validation
au moment du build (vmBytecodeArrayEncodingKey seule n'a aucun moyen d'obtenir la clé à l'exécution ; un getter seul
n'a aucune clé de compilation avec laquelle concorder). Elles n'ont en outre aucun effet si le tableau de bytecode n'est
pas réellement chiffré : vmBytecodeArrayEncoding: true doit donc aussi être activé - ou vmSelfDefending: true, qui
force l'activation interne de vmBytecodeArrayEncoding. Définissez les deux clés avec l'une de ces options.
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 contrôlée par l'obfuscateur :
- À la compilation.
vmBytecodeArrayEncodingKeyest 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 à laquelle se résout votre
vmBytecodeArrayEncodingKeyGetterest combinée à la même clé interne, reconstruite côté 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 en exactement la même chaîne
que celle passée dans vmBytecodeArrayEncodingKey. Aucune des deux pièces ne suffit 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 le contrôle de
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 côté client : un cookie, localStorage, une variable
globale ou un élément du DOM injecté par le serveur.
La clé doit exister avant l'exécution du code obfusqué :
Les autres sources synchrones fonctionnent de la même manière ; choisissez celle que votre application renseigne déjà :
Ne placez pas la clé dans le même fichier ou le même script que le code obfusqué. L'y intégrer annule tout l'intérêt :
une analyse statique du bundle récupérerait à la fois le code et sa clé. Stockez-la dans une source distincte, et
injectez la vmBytecodeArrayEncodingKey de compilation depuis une variable d'environnement ou un secret plutôt que de
la committer.
Récupérer la clé depuis votre backend (asynchrone)
Nécessite vmAsyncExecutor · v7.3.0+Un getter synchrone ne peut lire que ce qui se trouve déjà côté client. Pour récupérer la clé depuis votre
serveur - afin de pouvoir la conditionner à une authentification et la révoquer - le getter doit être asynchrone,
ce qui nécessite vmAsyncExecutor. Avec Async Executor activé, le
getter peut renvoyer une Promise, que la VM attend avant de s'exécuter.
Activer vmAsyncExecutor restreint aussi ce qui est virtualisé : dans ce mode, seules les fonctions async les plus
externes sont compilées dans la VM, et le code synchrone n'est pas virtualisé (le reste de l'obfuscation s'applique toujours). Si votre programme est surtout
synchrone, enveloppez le code à protéger dans une fonction async pour qu'il reste couvert - consultez
vmAsyncExecutor pour la règle complète.
Un getter qui renvoie une Promise nécessite vmAsyncExecutor. Cela ne peut pas être vérifié au moment du build :
un getter à Promise avec vmAsyncExecutor désactivé échoue donc à l'exécution.
Côté serveur, choisissez la clé à renvoyer en fonction de ce en quoi votre application a confiance : une session
validée, une vérification de licence, etc. Origin ou Referer seul n'authentifie pas un appelant, et les requêtes
GET de même origine peuvent omettre Origin. L'astuce : au lieu de rejeter les appelants non fiables, renvoyez une
mauvaise clé (VM_DECOY_KEY ci-dessous). Le code protégé échoue alors de lui-même (erreurs, résultats erronés
ou page qui ne répond plus), ce qui est plus discret qu'une erreur 401 évidente indiquant à l'attaquant exactement quoi
contourner.
Désactivez la mise en cache des réponses, afin que la clé d'un appelant ne soit jamais servie à un autre. Associez les clés à la bonne version du build, et déployez clés et bundles ensemble. Un client qui reçoit la vraie clé peut toujours l'inspecter à l'exécution.
Servez depuis ce point de terminaison exactement la même chaîne que celle passée dans vmBytecodeArrayEncodingKey au
moment du build. Le getter ci-dessus récupère une URL relative (/api/vm-key) : une copie du bundle hébergée sur
une autre origine demande donc /api/vm-key à cette origine-là et ne reçoit jamais votre clé ; la
clé leurre est ce que reçoit un appelant qui atteint votre point de terminaison, mais sans session de confiance (une
requête non authentifiée, un bundle volé servi en proxy via votre origine). Dans les deux cas, la vraie clé n'arrive
jamais et le code protégé ne s'exécute pas.
Ce qui est considéré comme « valide » dépend entièrement de l'application : une session authentifiée, une licence
signée, ou toute combinaison. Quelle que soit la source de la clé, enveloppez-la dans une Promise et Async Executor
l'attendra avant d'exécuter la VM.
Quand la clé ne correspond pas
Le code obfusqué ne fonctionne que si 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
code échoue à l'exécution : il produit des résultats erronés, lève une erreur d'exécution ordinaire ou cesse de
répondre.
Il n'existe volontairement aucun message d'erreur distinct propre à la clé : une clé invalide ne se distingue d'aucune autre défaillance à l'exécution. Ainsi, lorsqu'un bundle protégé par VM lève une erreur, renvoie des résultats erronés ou se fige uniquement une fois cette option en jeu, vérifiez d'abord le chemin de la clé : que le getter se résout bien sur la page, qu'il renvoie une chaîne non vide et qu'il renvoie la même valeur que celle utilisée pour le build.
