Dokumentation
/
Rezepte
/

Bytecode-Array-Codierungsschlüssel

Externalisierung des Bytecode-Array-Verschlüsselungsschlüssels

Pro

Stellen Sie Ihren eigenen VM-Bytecode-Verschlüsselungsschlüssel mit vmBytecodeArrayEncodingKey bereit und geben Sie ihn zur Laufzeit über einen Key-Getter zurück — außerhalb des Bundles gehalten, aus dem Client-Speicher gelesen oder von Ihrem Backend abgerufen.

Was diese Optionen bewirken

vmBytecodeArrayEncoding verschlüsselt das VM-Bytecode-Array, sodass es nicht als Klartext in der Ausgabe vorliegt. Standardmäßig wird der Verschlüsselungsschlüssel aus der Umgebung abgeleitet und auf dem Client rekonstruiert, sodass Sie ihn nie selbst handhaben. Das ist praktisch, aber das Schlüsselmaterial befindet sich weiterhin im Bundle.

Zwei Optionen ermöglichen es Ihnen, den Schlüssel aus dem Bundle herauszunehmen und selbst zu kontrollieren:

  • vmBytecodeArrayEncodingKey — der Schlüssel, den Sie zur Kompilierzeit angeben. Wenn gesetzt, wird er anstelle des standardmäßig aus der Umgebung abgeleiteten Schlüssels verwendet und ist in der obfuskierten Ausgabe nicht eingebettet.
  • vmBytecodeArrayEncodingKeyGetter — ein JavaScript-Ausdruck, der denselben Schlüssel zur Laufzeit zurückgibt. Er wird wortwörtlich eingebettet und im Browser ausgewertet, wenn der obfuskierte Code geladen wird.

Der Kernpunkt ist die Trennung: Da der Schlüssel nicht im Code steht, kann ihn ein rein statischer Scan des Bundles nicht wiederherstellen. Er muss zur Laufzeit dennoch vorhanden sein, damit der Code läuft, ist also nicht wirklich geheim — aber Sie entscheiden, woher er stammt und wer ihn zu sehen bekommt.

Wie die beiden Schlüssel kombiniert werden

Ihr Schlüssel wird niemals allein verwendet — auf beiden Seiten wird er mit einem internen Schlüssel vermischt, den der Obfuskator kontrolliert:

  • Kompilierzeit. vmBytecodeArrayEncodingKey wird mit einem internen Schlüssel kombiniert, den der Obfuskator ableitet, und das Bytecode-Array wird mit dem resultierenden gemischten Schlüssel codiert.
  • Laufzeit. Der Wert, zu dem Ihr vmBytecodeArrayEncodingKeyGetter aufgelöst wird, wird mit demselben internen Schlüssel kombiniert — auf dem Client aus verschiedenen Laufzeitfaktoren rekonstruiert —, um den Bytecode zu decodieren.

Da beide Seiten Ihren Schlüssel mit dem internen Schlüssel vermischen, muss der Getter zu exakt derselben Zeichenkette aufgelöst werden, die Sie als vmBytecodeArrayEncodingKey übergeben haben. Kein Teil genügt für sich allein: Ihr Schlüssel kann ohne den internen Schlüssel den Bytecode nicht decodieren, und der interne Schlüssel ist ohne Ihren nutzlos — weshalb die Kontrolle darüber, wer Ihren Schlüssel erhält, das ist, was den Code tatsächlich schützt.

Den Schlüssel zur Laufzeit bereitstellen

Standardmäßig ist der Getter synchron: Der Ausdruck muss den Schlüssel sofort zurückgeben, wenn der obfuskierte Code geladen wird. Lesen Sie ihn aus einer beliebigen Quelle, die bereits auf dem Client vorhanden ist — einem Cookie, localStorage, einer globalen Variable oder einem serverseitig injizierten DOM-Element.

JavaScriptObfuscator.obfuscate(sourceCode, {
    vmObfuscation: true,
    vmBytecodeArrayEncoding: true,
    vmBytecodeArrayEncodingKey: process.env.VM_KEY,       // e.g. 'mySecretKey123'
    vmBytecodeArrayEncodingKeyGetter: "window.__VM_KEY__" // returns the key at runtime
});

Der Schlüssel muss vor der Ausführung des obfuskierten Codes existieren:

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

Andere synchrone Quellen funktionieren genauso — wählen Sie diejenige, die Ihre App bereits befüllt:

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

Den Schlüssel von Ihrem Backend abrufen (async)

Erfordert vmAsyncExecutor · v7.3.0+

Ein synchroner Getter kann nur lesen, was bereits auf dem Client vorhanden ist. Um den Schlüssel von Ihrem Server abzurufen — sodass Sie ihn hinter einer Authentifizierung absichern und widerrufen können —, muss der Getter asynchron sein, und das erfordert vmAsyncExecutor. Wenn der Async-Executor aktiviert ist, darf der Getter ein Promise zurückgeben, und die VM wartet darauf, bevor sie ausgeführt wird.

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

Entscheiden Sie auf dem Server anhand dessen, was Ihre Anwendung als vertrauenswürdig einstuft, welchen Schlüssel Sie zurückgeben — eine gültige Sitzung, einen erwarteten Origin oder Referer, eine Lizenzprüfung und so weiter. Der Kniff: Statt nicht vertrauenswürdige Aufrufer abzulehnen, geben Sie einen falschen Schlüssel zurück. Der Bytecode wird dann zu Datenmüll decodiert und der geschützte Code schlägt von selbst fehl, was unauffälliger ist als ein offensichtlicher 401, der einem Angreifer genau sagt, was er umgehen muss.

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

Liefern Sie über diesen Endpunkt exakt dieselbe Zeichenkette aus, die Sie zur Build-Zeit als vmBytecodeArrayEncodingKey übergeben haben. Eine Kopie des Bundles, die außerhalb Ihrer Umgebung läuft, erhält den Köderschlüssel, entschlüsselt zu nichts und ist funktionslos.

Wenn der Schlüssel nicht übereinstimmt

Der obfuskierte Code funktioniert nur, wenn der Getter exakt denselben Schlüssel zurückgibt, der bei der Obfuskation verwendet wurde. Wenn sich die Schlüssel unterscheiden — oder der Getter undefined, null oder eine leere Zeichenkette zurückgibt —, erzeugt die Entschlüsselung einen falschen Keystream und der Code schlägt zur Laufzeit mit Datenmüll als Ausgabe oder einem gewöhnlichen Laufzeitfehler fehl.

Es gibt bewusst keine eigene, schlüsselspezifische Fehlermeldung: Ein fehlgeschlagener Schlüssel ist von jedem anderen Laufzeitfehler nicht zu unterscheiden. Wenn ein VM-geschütztes Bundle also erst dann einen Fehler wirft, sobald diese Option im Spiel ist, prüfen Sie zuerst den Schlüsselpfad — dass der Getter auf der Seite aufgelöst wird, eine nicht leere Zeichenkette zurückgibt und denselben Wert zurückgibt, mit dem Sie gebaut haben.