Dokumentation
/
Rezepte
/

Schlüssel für Bytecode Array Encoding

Schlüssel für Bytecode Array Encoding auslagern

Pro

Geben Sie mit vmBytecodeArrayEncodingKey Ihren eigenen Schlüssel zur Verschlüsselung des VM-Bytecodes vor und reichen 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.

Ansehen

Obfuscator.io Async Executor: Async Bytecode Key Getter and Async-Only VM Virtualization

Auf YouTube ansehen

Obfuscator.io Custom Bytecode Key: Compile-Time Key and Runtime Key Getter (Cookie, Fetch, Decoy Key)

Auf YouTube ansehen

Was diese Optionen bewirken

vmBytecodeArrayEncoding verschlüsselt das VM-Bytecode-Array, damit es nicht als Klartext in der Ausgabe steht. Standardmäßig wird der Schlüssel aus der Umgebung abgeleitet und auf dem Client rekonstruiert, sodass Sie nie damit in Berührung kommen. Das ist bequem, aber das Schlüsselmaterial befindet sich weiterhin im Bundle.

Mit zwei Optionen können Sie den Schlüssel aus dem Bundle herausnehmen und selbst verwalten:

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

Es geht um Trennung: Da der Schlüssel nicht im Code steht, kann eine rein statische Analyse des Bundles ihn nicht wiederherstellen. Zur Laufzeit muss er trotzdem vorhanden sein, damit der Code läuft, er ist also nicht wirklich geheim. Sie entscheiden jedoch, woher er kommt und wer ihn zu sehen bekommt.

Diese beiden Optionen gehören zusammen, und der Obfuscator setzt das durch: Wird nur eine von beiden gesetzt, ist das ein Validierungsfehler beim Build (vmBytecodeArrayEncodingKey allein hat keine Möglichkeit, den Schlüssel zur Laufzeit zu beschaffen; ein Getter allein hat keinen Schlüssel zur Kompilierzeit, mit dem er übereinstimmen könnte). Außerdem wirken sie nur, wenn das Bytecode-Array tatsächlich verschlüsselt wird. Daher muss auch vmBytecodeArrayEncoding: true aktiviert sein - oder vmSelfDefending: true, das vmBytecodeArrayEncoding intern erzwingt. Setzen Sie beide Schlüssel zusammen mit einer dieser Optionen.

Wie die beiden Schlüssel kombiniert werden

Ihr Schlüssel wird nie allein verwendet, sondern auf beiden Seiten mit einem internen Schlüssel gemischt, den der Obfuscator kontrolliert:

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

Da beide Seiten Ihren Schlüssel mit dem internen Schlüssel mischen, muss der Getter exakt denselben String liefern, den Sie als vmBytecodeArrayEncodingKey übergeben haben. Keiner der beiden Teile genügt allein: Ihr Schlüssel ohne den internen Schlüssel kann den Bytecode nicht decodieren, und der interne Schlüssel ist ohne Ihren wertlos. Deshalb schützt tatsächlich die Kontrolle darüber, wer Ihren Schlüssel erhält, den Code.

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 Quelle, die auf dem Client bereits vorhanden ist: einem Cookie, localStorage, einer globalen Variablen oder einem vom Server eingefügten DOM-Element.

JavaScript

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

JavaScript

Andere synchrone Quellen funktionieren genauso. Wählen Sie diejenige, die Ihre Anwendung ohnehin befüllt:

JavaScript

Halten Sie den Schlüssel aus derselben Datei bzw. demselben Skript wie den obfuskierten Code heraus. Ihn dort einzubetten, macht den ganzen Zweck zunichte: Eine statische Analyse des Bundles würde sowohl den Code als auch seinen Schlüssel wiederherstellen. Legen Sie ihn in einer separaten Quelle ab, und übergeben Sie den vmBytecodeArrayEncodingKey für die Kompilierzeit aus einer Umgebungsvariablen oder einem Secret, statt ihn zu committen.

Den Schlüssel vom Backend abrufen (asynchron)

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, damit Sie ihn hinter eine Authentifizierung stellen und widerrufen können, muss der Getter asynchron sein, und das erfordert vmAsyncExecutor. Mit aktiviertem Async Executor darf der Getter ein Promise zurückgeben, und die VM wartet darauf, bevor sie ausgeführt wird.

Das Aktivieren von vmAsyncExecutor schränkt auch ein, was virtualisiert wird: In diesem Modus werden nur die äußersten async-Funktionen in die VM kompiliert, synchroner Code wird nicht virtualisiert (die übrige Obfuskierung gilt weiterhin). Wenn Ihr Programm überwiegend synchron ist, verpacken Sie den zu schützenden Code in eine async-Funktion, damit er weiterhin abgedeckt wird; die vollständige Regel finden Sie unter vmAsyncExecutor.

JavaScript

Ein Getter, der ein Promise zurückgibt, erfordert vmAsyncExecutor. Das lässt sich beim Build nicht prüfen, daher schlägt ein Promise-Getter bei ausgeschaltetem vmAsyncExecutor zur Laufzeit fehl.

Entscheiden Sie auf dem Server anhand dessen, was Ihre Anwendung als vertrauenswürdig ansieht, welcher Schlüssel zurückgegeben wird: eine validierte Sitzung, eine Lizenzprüfung und so weiter. Origin oder Referer allein authentifizieren keinen Aufrufer, und GET-Anfragen vom selben Ursprung können Origin weglassen. Der Kniff: Statt nicht vertrauenswürdige Aufrufer abzuweisen, geben Sie einen falschen Schlüssel zurück (unten VM_DECOY_KEY). Der geschützte Code scheitert dann von selbst (Fehler, falsche Ergebnisse oder eine Seite, die nicht mehr reagiert). Das ist unauffälliger als ein offensichtliches 401, das einem Angreifer genau verrät, was er umgehen muss.

Deaktivieren Sie das Caching der Antwort, damit der Schlüssel eines Aufrufers nie an einen anderen ausgeliefert wird. Binden Sie Schlüssel an die richtige Build-Version, und deployen Sie Schlüssel und Bundles gemeinsam. Ein Client, der den echten Schlüssel erhält, kann ihn zur Laufzeit dennoch einsehen.

JavaScript

Liefern Sie über diesen Endpunkt exakt denselben String aus, den Sie beim Build als vmBytecodeArrayEncodingKey übergeben haben. Der Getter oben ruft eine relative URL (/api/vm-key) ab. Eine Kopie des Bundles, die auf einem anderen Origin gehostet wird, fordert /api/vm-key daher von diesem Origin an und erhält Ihren Schlüssel nie; den Köder-Schlüssel bekommt ein Aufrufer, der Ihren Endpunkt zwar erreicht, aber ohne vertrauenswürdige Sitzung (eine nicht authentifizierte Anfrage, ein gestohlenes Bundle, das über Ihren Origin weitergeleitet wird). In beiden Fällen kommt der echte Schlüssel nie an, und der geschützte Code wird nicht ausgeführt.

Was als „gültig“ gilt, hängt ganz von Ihrer Anwendung ab: eine authentifizierte Sitzung, eine signierte Lizenz oder eine beliebige Kombination. Was auch immer den Schlüssel erzeugt, verpacken Sie es in ein Promise, und der Async Executor wartet darauf, bevor er die VM ausführt.

Wenn der Schlüssel nicht übereinstimmt

Der obfuskierte Code funktioniert nur, wenn der Getter exakt denselben Schlüssel zurückgibt, der bei der Obfuskierung verwendet wurde. Weichen die Schlüssel voneinander ab oder gibt der Getter undefined, null oder einen leeren String zurück, scheitert der Code zur Laufzeit: Er liefert falsche Ergebnisse, wirft einen gewöhnlichen Laufzeitfehler oder reagiert nicht mehr.

Es gibt bewusst keine eigene, schlüsselspezifische Fehlermeldung: Ein falscher Schlüssel ist von keinem anderen Laufzeitfehler zu unterscheiden. Wenn ein VM-geschütztes Bundle also erst dann Fehler wirft, falsche Ergebnisse liefert oder einfriert, sobald diese Option im Spiel ist, prüfen Sie zuerst den Weg des Schlüssels: ob der Getter auf der Seite aufgelöst wird, einen nicht leeren String zurückgibt und denselben Wert liefert, mit dem Sie den Build erstellt haben.