Документация
/

Решение проблем

/

Как избежать конфликтов идентификаторов

Как избежать конфликтов идентификаторов между обфусцированными файлами

Когда несколько VM-обфусцированных файлов попадают в один бандл, они могут объявить один и тот же идентификатор верхнего уровня и уронить страницу на этапе разбора. Здесь объясняется, почему так происходит и как это исправить.

Симптом

Сборка проходит без ошибок, но браузер выбрасывает исключение на этапе разбора, ещё до запуска приложения:

Текст

Чтобы узнать, сколько чанков объявляют имя из ошибки, посчитайте файлы, содержащие его объявление:

Текст

-l выводит каждый подходящий файл один раз, а -w сопоставляет только целые слова, поэтому vmdX не учитывается. var не учитывается, потому что повторное объявление var само по себе не является ошибкой. Результат больше 1 означает, что имя объявлено более чем в одном чанке. Замените vmd на имя из вашего сообщения об ошибке.

Конфликты идентификаторов имеют значение, только когда объявления находятся в одной области видимости. Повторение одного имени в разных модулях или замыканиях ещё не доказывает конфликт; доказательство - ошибка разбора выше.

Почему так происходит

VM-пресеты используют Identifier Names Generator со значением mangled-shuffled. Он перебирает небольшой алфавит в перемешанном порядке, а при VM-обфускации каждая переименованная глобальная переменная получает префикс vm (он добавляется перед любым заданным вами identifiersPrefix, так что checkout_ превращается в vm_checkout_...). Перемешанный порядок кешируется на время работы процесса, поэтому файлы, обфусцированные в одном процессе или с одним и тем же фиксированным seed, берут имена из одной последовательности: первая глобальная переменная в каждом файле получает одинаковое имя, вторая - другое одинаковое имя, и так далее.

Каждый файл обфусцируется независимо, и для каждого генератор начинает свою последовательность заново. Когда два файла оказываются в одной области видимости, имена конфликтуют. Два объявления let vmd верхнего уровня попадают в одну область видимости, и парсер отвергает второе.

Каждый VM-обфусцированный файл объявляет одно имя среды выполнения верхнего уровня без суффикса, и этого достаточно для конфликта. renameGlobals: true сильно усугубляет ситуацию: каждое объявление верхнего уровня получает короткое имя vm*, а собственные имена среды выполнения теряют свой уникальный суффикс.

Исправления

Лучше сначала собрать бандл, а затем обфусцировать его один раз. Если вы всё же обфусцируете файлы по отдельности и скрипты разделяют глобальную область видимости, выберите один из вариантов:

  • Включите randomIdentifiersPrefix (рекомендуется)

    Каждый запуск обфускации получает случайный префикс, который добавляется к каждому глобальному идентификатору (при VM-обфускации он заменяет префикс vm по умолчанию). Имена из разных файлов больше не делят одно пространство имён, поэтому конфликты исчезают, и вам не нужно вручную согласовывать префиксы.

  • Задайте уникальный identifiersPrefix для каждого файла

    Вручную передавайте свой префикс при обфускации каждого файла (например, identifiersPrefix: 'auth_' для одного, checkout_ для другого). Это работает, но при большом числе файлов легко ошибиться - лучше использовать случайный вариант выше.

    JavaScript

  • Переключите identifierNamesGenerator на hexadecimal

    Шестнадцатеричные имена используют гораздо большее пространство ключей, поэтому вероятность того, что два файла выдадут одинаковый идентификатор, намного ниже, но уникальность не гарантируется. Компромисс: идентификаторы длиннее, чем при mangled-shuffled, поэтому бандл становится немного больше.

  • Используйте пакетную обработку нескольких файлов в интерфейсе или проверьте плагин бандлера

    Панель управления добавляет отдельный префикс каждому файлу в пределах одного пакета из нескольких файлов (платные тарифы); файлы из разных пакетов всё равно могут конфликтовать. Если вы используете плагин бандлера, проверьте его поведение, а не предполагайте, что он делает то же самое. Если вы сами вызываете пакет javascript-obfuscator или API, префикс нужно включить самостоятельно.

Чтобы проверить исправление, пересоберите и перезагрузите собранное приложение целиком и убедитесь, что SyntaxError исчез. Имя из прежнего сообщения об ошибке больше не должно объявляться более чем в одном чанке; префикс меняет все сгенерированные имена, поэтому команда grep выше говорит только об этом конкретном имени, а не о новых.

Связанные опции