Dokumentacja
/

Rozwiązywanie problemów

/

Unikanie kolizji identyfikatorów

Unikanie kolizji identyfikatorów między zobfuskowanymi plikami

Gdy kilka plików zobfuskowanych przez VM trafia do tego samego bundle'a, mogą one zadeklarować ten sam identyfikator najwyższego poziomu i wywołać awarię strony już na etapie parsowania. Wyjaśniamy, dlaczego tak się dzieje i jak temu zaradzić.

Objaw

Build przebiega bez problemów, ale przeglądarka zgłasza błąd na etapie parsowania, zanim aplikacja się uruchomi:

Tekst

Aby sprawdzić, ile chunków deklaruje nazwę z komunikatu błędu, policz pliki zawierające jej deklarację:

Tekst

-l wypisuje każdy pasujący plik raz, a -w dopasowuje tylko całe słowa, więc vmdX nie jest liczone. var pominięto, ponieważ powtórzenie deklaracji var samo w sobie nie jest błędem. Wynik większy niż 1 oznacza, że nazwa jest zadeklarowana w więcej niż jednym chunku. Zastąp vmd nazwą z Twojego komunikatu błędu.

Kolizje identyfikatorów mają znaczenie tylko wtedy, gdy deklaracje dzielą ten sam zakres. Ta sama nazwa powtórzona w osobnych modułach lub domknięciach nie dowodzi kolizji; dowodzi jej dopiero powyższy błąd parsowania.

Dlaczego tak się dzieje

Presety VM używają generatora mangled-shuffled opcji Identifier Names Generator. Przechodzi on przez niewielki alfabet w przetasowanej kolejności, a przy obfuskacji VM każda zmienna globalna o zmienionej nazwie otrzymuje prefiks vm (dodawany przed każdym ustawionym przez Ciebie identifiersPrefix, więc checkout_ zmienia się w vm_checkout_...). Przetasowana kolejność jest zapamiętywana w obrębie procesu, więc pliki obfuskowane w tym samym procesie albo z tym samym stałym seed korzystają z tej samej sekwencji - pierwsza zmienna globalna w każdym pliku ma tę samą nazwę, druga również wspólną, i tak dalej.

Każdy plik jest obfuskowany niezależnie, a generator dla każdego z nich zaczyna swoją sekwencję od początku. Gdy dwa pliki trafią do tego samego zakresu, nazwy kolidują. Dwie deklaracje najwyższego poziomu let vmd lądują w tym samym zakresie, a parser odrzuca drugą z nich.

Każdy plik obfuskowany przez VM deklaruje jedną nazwę środowiska uruchomieniowego najwyższego poziomu bez sufiksu, a to wystarczy do kolizji. renameGlobals: true znacznie to pogarsza: każda deklaracja najwyższego poziomu staje się krótką nazwą vm*, a własne nazwy środowiska uruchomieniowego tracą swój unikalny sufiks.

Rozwiązania

Najlepiej najpierw zbudować bundle, a potem obfuskować go jednorazowo. Jeśli jednak obfuskujesz pliki osobno, a skrypty dzielą globalny zakres, wybierz jedno z poniższych rozwiązań:

  • Włącz randomIdentifiersPrefix (zalecane)

    Każde uruchomienie obfuskacji otrzymuje losowy prefiks dodawany na początku każdego globalnego identyfikatora (przy obfuskacji VM zastępuje on domyślny prefiks vm). Nazwy z różnych plików nie dzielą już przestrzeni nazw, więc kolizje znikają bez konieczności ręcznego uzgadniania prefiksów.

  • Ustaw unikalny identifiersPrefix dla każdego pliku

    Podczas obfuskacji każdego pliku ręcznie przekaż inny prefiks (np. identifiersPrefix: 'auth_' dla jednego, checkout_ dla drugiego). To skuteczne, ale przy wielu plikach łatwo o pomyłkę, więc lepiej wybrać opcję losową opisaną wyżej.

    JavaScript

  • Przełącz identifierNamesGenerator na hexadecimal

    Nazwy szesnastkowe korzystają ze znacznie większej przestrzeni kluczy, więc prawdopodobieństwo, że dwa pliki wygenerują ten sam identyfikator, jest dużo mniejsze, ale unikalność nie jest gwarantowana. Koszt: identyfikatory są dłuższe niż w wyniku mangled-shuffled, więc bundle jest nieco większy.

  • Użyj interfejsu obfuskacji wielu plików naraz albo sprawdź wtyczkę bundlera

    Panel dodaje osobny prefiks do każdego pliku w ramach jednej partii wielu plików (plany płatne); pliki z różnych partii nadal mogą kolidować. Jeśli używasz wtyczki bundlera, sprawdź jej zachowanie, zamiast zakładać, że robi to samo. Jeśli sam wywołujesz pakiet javascript-obfuscator lub API, musisz sam włączyć prefiks.

Aby zweryfikować poprawkę, przebuduj i ponownie wczytaj połączoną aplikację, a następnie upewnij się, że SyntaxError zniknął. Nazwa ze starego komunikatu błędu nie powinna już być zadeklarowana w więcej niż jednym chunku; prefiks zmienia każdą wygenerowaną nazwę, więc powyższy grep mówi tylko o tej konkretnej nazwie, a nie o nowych.

Powiązane opcje