Модель загроз AfterPack: захищена поверхня

Матеріал для безпекового рев'ю AfterPack: актив, який він захищає, що відновлює кожен клас зловмисників, як зберігається секрет, де закінчується поточний обсяг і які засоби контролю працюють поруч із ним.

AfterPack захищає один актив: JavaScript-артефакт, який видає ваша збірка. Він переписує цей артефакт так, щоб читання, зняття відбитка чи патчинг коштували зловмисникові справжньої роботи, а інструменти, зроблені під одну збірку, ламалися на наступній.

Ця сторінка написана для безпекового рев'ю. Вона описує захищену поверхню, що відновлює кожен клас зловмисників, точку, де контроль на етапі збірки перестає діяти, і засоби контролю, які покривають решту.

Захищена поверхня

Що захищеноАтака, яку це знімає з порядку денногоВластивість, що робить роботу
Читабельність бандла, який ви випускаєтеВставити бандл в інструмент чи модель і отримати назад ваш вихідний кодІдентифікатори перейменовано, рядки закодовано, потік керування сплощено, а тотожності злито, тож прочитати бандл назад до вашого вихідного коду коштує реальної роботи, яку доводиться повторювати з кожною збіркою
Структура вашого бандлаОдин раз написати деобфускатор, сигнатуру чи скрипт-патч і повторно використовувати їх між релізамиНовий seed для кожної збірки, тож інструменти, написані під шаблони однієї збірки, ламаються на наступній
Атрибуція вашої реалізаціїДовести, що випущений бандл — це ваш код, ваша бібліотека чи ваш алгоритмСтатичний читач мусить повторювати роботу з відновлення класу «Перейменовано й закодовано» на кожній збірці, перш ніж зможе зіставити результат із вашим; класи, що знищують походження й прибрали б цей збіг повністю, сьогодні не створюються
Рядковий матеріал, з яким ви порівнюєте значенняПошук у бандлі токена чи рядка перевірки через grepМінімальне кодування рядків, а для перевірки на рівність нематеріалізація. На light числа лишаються читабельними
Цілісність артефакту під час використанняПропатчити одну перевірку і випустити пропатчену збіркуНовий seed переносить місце патча в кожному релізі. Самоперевірка цілісності виявляє зміни лише у власній таблиці перевірок

Усе нижче уточнює ці п'ять рядків: кого треба перемогти, як далеко сягає кожна властивість і чого вона не досягає.

Класи зловмисників

Дві осі, а не одна шкала. Статичний зловмисник читає байти: grep, інструменти для AST, прохід деобфускатора або передова модель, яка пояснює код, не виконуючи його. Динамічний зловмисник запускає артефакт: у пропатченому середовищі виконання, з перехопленими вбудованими функціями або на записаній трасі виконання, яку відтворюють офлайн. Трансформація може бути сильною проти читача і слабкою проти того, хто запускає код, а змішування цих двох — найпоширеніше перебільшення в цій категорії.

Шкала нижче впорядкована за можливостями зловмисника. Вартість відносна до інших рядків, а не абсолютна величина.

ЩабельЗловмисникМасштабВартість для зловмисникаРезультат
A0Статичні шаблонні інструменти: grep, AST-матчери, детерміновані проходи деобфускаціїодна збіркаМізернаВідновлює те, що лишилося відкритим текстом. Готові деобфускатори не додають нічого понад grep (виміряні результати).
A1Модель наосліп: одне прочитання, без виконання, без інструментіводна збіркаМізернаРозвернула більшу частину прочитаного: на трьох малих програмах повністю розвернула всі три на light, дві на medium і одну на extreme, а там, де не змогла відтворити програму, що запускається, однаково відновила більшість закладених секретів (виміряні результати).
A2Агентна модель із виконанням, інструментами та бюджетомодна збіркаНизька, на кожну збіркуЦя збірка не встоює: запуск коду відкриває значення, які він використовує. Інструменти, зроблені під форму цієї збірки, доводиться переробляти для наступної.
A3Модель, навчена на великій вибірці власного результату AfterPackувесь розподіл, а не одна збіркаОдноразова інвестиція, далі мізерна на кожну збіркуНе виміряно. Див. нижче.
A4Інструментований динамічний аналіз: перехоплені вбудовані функції, записане виконання, знімки heapодна збірка, дешево повторюєтьсяЧас аналітика, на кожну збіркуПадає для рядків: runtime-хук відновив 96 із 97 на кожному пресеті (виміряні результати). Див. межу.
A5Привілейоване середовище виконання: пропатчений браузер, нативні хуки нижче рівня JavaScriptодна збіркаВисокі витрати на підготовку, далі мізерніПадає для всього, що виконується на клієнті.

Щаблі накопичуються за можливостями, а не за ймовірністю. A0 покриває переважну більшість реальних атак на випущений JavaScript: хтось запускає безкоштовний інструмент або вставляє ваш бандл у вікно чату. A5 — рідкісний і дорогий фінал, з яким більшість продуктів ніколи не стикається.

A0–A2 атакують одну збірку. Новий seed для кожної збірки, якщо ви його не зафіксували, змінює форму, тож розпізнавач чи патч, написаний під одну збірку, доводиться переписувати для наступної. Значень він не ховає: усе, що використовує код, може прочитати той, хто його запускає.

A3 атакує весь розподіл результатів. Модель, навчена на достатньо великій вибірці, вчиться бути інваріантною до варіативності між збірками, і ротація вашого сіду їй нічого не коштує. Що досі допомагає, так це прицільність: Pro застосовує важчий пресет до позначених вами ділянок і додає два типи трансформацій, які вмикаються явно: transforms.selfIntegrity.enabled і transforms.comparisonHardening.enabled. Позначайте те, що справді важливо; див. Найкращі практики.

A4 і A5 повністю виходять за межі статичного артефакту. Межа описує обидва.

Виміряні результати

Що кожен зловмисник відновив із результату рушія 0.2.2, виміряно в жовтні 2026 року на п'яти програмах із закладеними секретами та на реальних продакшн-бандлах. Рядок передової моделі — окремий замір у жовтні 2026 року на рушії 0.2.6.

Зловмисникlightmediumhard і extreme
Шаблонні інструменти: webcrack, restringer, synchrony, terserНічого понад grepНічого понад grepНічого понад grep
Grep 42 закладених чисел421818
Статичне обчислення результату92–100% рядків96–98% рядків після проходу очищення, що зберігає поведінку96–98% рядків після того самого проходу
Runtime-хук на 15 рядків на вбудованій функції96 із 97 рядків96 із 97 рядків96 із 97 рядків
Передова модель, наосліп, без інструментів і без виконанняУсі 3 програми повністю розвернуто2 із 3 повністю розвернуто; третя віддала 12 із 17 секретів без відтвореної програми, що запускаєтьсяЛише extreme: 1 із 3 повністю розвернуто (9 із 9 секретів); інші віддали 12 із 17 і 2 із 3 секретів без відтворених програм, що запускаються

У рядку передової моделі Claude Opus 5.5 отримувала лише обфускований файл, а 5 файлів, від яких вона відмовилася, пішли до Claude Opus 4.8; «повністю розвернуто» означає, що відтворений код друкує ті самі тестові вектори, що й оригінал, і містить кожен закладений секрет. Застереження: малий корпус із трьох програм, одна спроба на програму й пресет, і зловмисник лише Claude.

Що захищає обфускація

AfterPack має на меті дві властивості. Перша — ціна: відновлення збірки має коштувати більше, ніж те, що вона захищає. Друга — перевага в ритмі релізів: ви оновлюєтеся швидше, ніж інструменти зловмисника узагальнюються на наступну збірку. Жоден обфускатор, зокрема AfterPack, не робить відновлення неможливим, і ніщо на цій сторінці не слід читати як таке твердження.

Стандартний пресет перейменовує ідентифікатори й кодує рядкові літерали. Починаючи з medium, AfterPack робить більше: потік керування сплощено, тотожності злито, а логіку переписано в еквівалентні форми, які стандартні інструменти не можуть згорнути назад. Зловмисник, який розвертає цей результат, може відновити робочу програму, але лише після реальної роботи з розпізнавання шаблонів, якої вимагають ці трансформації, а інструмент, написаний під форми однієї збірки, ламається на наступній. Класи відновлення розбивають це на класи, з якими стикається статичний читач.

Сід seed для кожної збірки за замовчуванням випадковий, тож дві збірки з того самого коду виходять структурно різними всюди. Інструменти, написані під шаблони збірки N, ламаються на збірці N+1, а значення, які хтось уже прочитав зі збірки N, лишаються прочитаними. Ця властивість окупається, лише якщо ви ротуєте збірки; Найкращі практики і Збірки та CI пояснюють, як вбудувати перезбірки в релізний конвеєр.

Ніщо з цього саме по собі не приховує секрет. Для цього потрібен інший механізм.

Захист секрету

Секрет можна дістати з будь-якої програми, що поводиться так само, як ваша, зокрема з тієї, яку статичний читач відновлює із захищеної ділянки. Перебудова коду навколо секрету нічого для нього не робить.

Від того, хто читає байти, секрет захищає нематеріалізація, описана в розділі Як уціліють секрети. Параметр, що її забезпечує, transforms.comparisonHardening.enabled, належить до Pro, вимкнений за замовчуванням і працює однаково на кожному рівні пресету.

Проти того, хто запускає ваш код, діє межа. Варіативність між збірками підвищує вартість повторного видобування секрету після кожної ротації. Універсальний хук у середовищі виконання, націлений на рушій JavaScript, коштує однаково в будь-якому разі, бо не залежить від структури AfterPack. Як працює AfterPack ставить той самий механізм поруч із тим, що вже робить стандартний результат.

Межа

Зловмисник, який запускає ваш код в інструментованому середовищі виконання, може дістатися до будь-якого значення, яке використовує сам код. Якщо запущеній програмі воно потрібне, наполегливий динамічний зловмисник може його побачити. AfterPack робить це значення дорогим для пошуку і дешевим для ротації. Він не робить його невідновлюваним.

Тримайте серверні повноваження подалі від клієнта

Ключам підпису, довготривалим обліковим даним і всьому, що зловмисник міг би повторно використати чи перепродати, місце на сервері, хоч би який обфускатор ви використовували.

Це обмеження не властиве лише AfterPack. Кожен обфускатор етапу збірки впирається в ту саму стіну, щойно зловмисник контролює середовище виконання. Що AfterPack зберігає за цією стіною, так це форму наступного релізу: інструменти, зроблені під одну збірку, доводиться переробляти для наступної.

Захист від втручання

Самоперевірка цілісності, transforms.selfIntegrity.enabled, додає перевірку над власною таблицею перевірок. Вона виявляє лише зміну цієї таблиці. Зміну будь-де ще у вашому коді, наприклад пропатчений return true, не виявлено.

Пасивного спостереження вона теж не виявляє: хук, що логує значення, читання heap чи нативна інструментація не змінюють нічого з того, що вона перевіряє. Це налаштування Pro, вимкнене за замовчуванням і глобальне; йому потрібен код рівня medium або вище, до якого можна прикріпитися, тож збірка на light містить його лише всередині ділянки, піднятої до такого рівня. preset=hard залишає його вимкненим і натомість піднімає ділянку до цільової складності 12 з увімкненим мінімальним кодуванням рядків.

Що AfterPack не замінює

AfterPack — один засіб контролю в стеку, і безпекове рев'ю має бачити, де його межі. Кожен рядок нижче описує поточну зону дії засобу контролю на етапі збірки і засіб, що покриває решту. Зона дії змінюється з виходом нових можливостей продукту; публічна дорожня карта — єдине місце, де AfterPack повідомляє, що буде далі.

Засіб контролюЩо AfterPack дає сьогодніЩо покриває решту
Захист на рівні запитів (боти, скрапінг, зловживання)Скрапер, якому потрібні структуровані дані з вашого бандла, мусить спочатку його розвернути. AfterPack діє на артефакт і не бачить запиту.Сервіс challenge-response (reCAPTCHA, hCaptcha, Arkose) плюс обмеження частоти запитів на сервері за IP, сесією або API-ключем.
Цілісність клієнта (чити, автоматизація, пропатчені клієнти)Автор читу чи автоматизації, який працює проти клієнта з preset=hard і поліморфізмом між збірками, у кожному релізі наново проводить реальний аналіз, замість того щоб один раз пропатчити відоме зміщення. AfterPack підвищує цю вартість; арбітром він не є.Валідація влучань, переходів стану та результатів на стороні сервера, де клієнт лише відображає рішення, які сервер уже ухвалив.
Цілісність доставки (проксі, CDN, розширення)AfterPack захищає байти, які створює. Він не контролює шлях, яким вони проходять, а розширення, що використовує власний API браузера для блокування запитів, вирішує, що завантажувати, ще до виконання будь-якого JavaScript.Subresource Integrity (integrity="sha384-…"), щоб браузер відмовлявся від бандла, який не збігається з хешем вашої збірки, плюс валідація на сервері всього, на що може вплинути посередник.
Безпека застосунку (баги, ін'єкції, зламана автентифікація)Обфускація сповільнює пошук вади через читання вихідного коду. Вона не прибирає ваду, а той, хто дістається до неї через запущену програму, вашого вихідного коду взагалі не читає.Виправте баг. npx afterpack@latest audit сканує живий сайт на те, що він уже видає назовні.
Рішення про довіру до клієнтаПоліморфізм між збірками перетворює одноразовий патч на регулярні витрати на повторний аналіз.Валідація на боці сервера, нижче.

Не заміна валідації на боці сервера

Усі рядки вище мають спільну першопричину: перевірка ліцензії, платіжний гейт, правило прав доступу чи feature flag, які мають справді діяти, — це рішення, яке клієнт ухвалює сам про себе, і той, хто контролює цей клієнт, може його підробити. Це властивість виконання коду на клієнті, а не прогалина конкретного обфускатора, і жодна трансформація на етапі збірки цього не закриває.

Для всього, що має витримати ворожий клієнт, як-от ліцензування, платежі, права доступу чи результати матчів, ухвалюйте рішення на сервері, а клієнт хай лише його відображає. Внесок AfterPack економічний, і він реальний: він підвищує регулярну вартість атаки на те, що справді виконується на клієнті.

Далі