Dokumentacja
/
Przepisy
/

Klucz kodowania tablicy bajtkodu

Eksternalizacja klucza kodowania tablicy bajtkodu

Pro

Podaj własny klucz szyfrowania bajtkodu VM za pomocą vmBytecodeArrayEncodingKey i przekaż go z powrotem w czasie działania poprzez getter klucza — trzymany poza bundlem, odczytywany z magazynu klienta lub pobierany z Twojego backendu.

Co robią te opcje

vmBytecodeArrayEncoding szyfruje tablicę bajtkodu VM, dzięki czemu nie znajduje się ona w kodzie wynikowym jako zwykły tekst. Domyślnie klucz szyfrowania jest wyprowadzany ze środowiska i rekonstruowany po stronie klienta, więc nigdy nie masz z nim do czynienia. Jest to wygodne, ale materiał klucza wciąż znajduje się w bundlu.

Dwie opcje pozwalają wyjąć klucz z bundla i kontrolować go samodzielnie:

  • vmBytecodeArrayEncodingKey — klucz, który podajesz w czasie kompilacji. Gdy jest ustawiony, jest używany zamiast domyślnego klucza wyprowadzanego ze środowiska i nie jest osadzany w zaciemnionym kodzie wynikowym.
  • vmBytecodeArrayEncodingKeyGetter — wyrażenie JavaScript, które zwraca ten sam klucz w czasie działania. Jest osadzane dosłownie i wykonywane w przeglądarce, gdy ładowany jest zaciemniony kod.

Chodzi o rozdzielenie: ponieważ klucz nie znajduje się w kodzie, czysto statyczne skanowanie bundla nie jest w stanie go odzyskać. Klucz musi jednak być obecny w czasie działania, aby kod mógł się wykonać, więc nie jest naprawdę tajny — ale to Ty decydujesz, skąd pochodzi i kto może go zobaczyć.

Jak łączą się oba klucze

Twój klucz nigdy nie jest używany samodzielnie — po obu stronach jest mieszany z wewnętrznym kluczem kontrolowanym przez obfuskator:

  • Czas kompilacji. vmBytecodeArrayEncodingKey jest łączony z wewnętrznym kluczem wyprowadzanym przez obfuskator, a tablica bajtkodu jest kodowana wynikowym kluczem mieszanym.
  • Czas działania. Wartość, do której rozwiązuje się Twój vmBytecodeArrayEncodingKeyGetter, jest łączona z tym samym wewnętrznym kluczem, rekonstruowanym po stronie klienta na podstawie różnych czynników czasu działania, aby zdekodować bajtkod.

Ponieważ obie strony mieszają Twój klucz z kluczem wewnętrznym, getter musi rozwiązywać się do dokładnie tego samego ciągu znaków, który przekazałeś jako vmBytecodeArrayEncodingKey. Żaden z tych elementów nie wystarcza sam z siebie: Twój klucz bez klucza wewnętrznego nie zdekoduje bajtkodu, a klucz wewnętrzny jest bezużyteczny bez Twojego — dlatego to kontrola nad tym, kto otrzymuje Twój klucz, faktycznie chroni kod.

Dostarczanie klucza w czasie działania

Domyślnie getter jest synchroniczny: wyrażenie musi zwrócić klucz natychmiast, gdy ładowany jest zaciemniony kod. Odczytaj go z dowolnego źródła, które jest już obecne po stronie klienta — z ciasteczka, localStorage, zmiennej globalnej lub elementu DOM wstrzykniętego przez serwer.

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

Klucz musi istnieć zanim uruchomi się zaciemniony kod:

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

Inne synchroniczne źródła działają tak samo — wybierz to, które Twoja aplikacja już wypełnia:

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

Pobieranie klucza z Twojego backendu (asynchronicznie)

Wymaga vmAsyncExecutor · v7.3.0+

Synchroniczny getter może odczytać tylko to, co już znajduje się po stronie klienta. Aby pobrać klucz z Twojego serwera — tak abyś mógł ograniczyć do niego dostęp za pomocą uwierzytelniania i go unieważnić — getter musi być asynchroniczny, a to wymaga vmAsyncExecutor. Po włączeniu asynchronicznego executora getter może zwrócić Promise, a VM czeka na niego przed uruchomieniem.

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

Na serwerze zdecyduj, który klucz zwrócić, na podstawie tego, czemu ufa Twoja aplikacja — ważnej sesji, oczekiwanego nagłówka Origin lub Referer, weryfikacji licencji itd. Sztuczka: zamiast odrzucać niezaufanych wywołujących, zwróć błędny klucz. Bajtkod dekoduje się wówczas do bezsensownych danych, a chroniony kod zawodzi sam z siebie, co jest bardziej dyskretne niż oczywisty 401, który mówi atakującemu dokładnie, co ma obejść.

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

Zwracaj z tego punktu końcowego dokładnie ten sam ciąg znaków, który przekazałeś jako vmBytecodeArrayEncodingKey w czasie budowania. Kopia bundla uruchomiona poza Twoim środowiskiem otrzymuje klucz-wabik, deszyfruje się do niczego i pozostaje bezużyteczna.

Gdy klucz nie pasuje

Zaciemniony kod działa tylko wtedy, gdy getter zwraca dokładnie ten sam klucz, który został użyty podczas zaciemniania. Jeśli klucze się różnią — lub getter zwraca undefined, null albo pusty ciąg znaków — deszyfrowanie wytwarza błędny strumień klucza, a kod zawodzi w czasie działania, dając bezsensowny wynik lub zwykły błąd czasu wykonania.

Celowo nie ma osobnego, specyficznego dla klucza komunikatu o błędzie: nieudany klucz jest nie do odróżnienia od jakiejkolwiek innej awarii w czasie działania. Dlatego gdy chroniony przez VM bundle zgłasza błąd dopiero wtedy, gdy ta opcja jest w użyciu, sprawdź najpierw ścieżkę klucza — czy getter rozwiązuje się na stronie, zwraca niepusty ciąg znaków i zwraca tę samą wartość, z którą zbudowałeś kod.