Super App з міні-програмами — це, по суті, операційна система всередині операційної системи. Хост-додаток завантажує та виконує код від сторонніх розробників. Якщо цей код може читати дані інших міні-програм або основного додатка — уся архітектура безпеки розвалюється. Ми пропонуємо реалізацію ізольованої пісочниці під ключ, гарантуючи, що кожна міні-програма працює в надійно обмеженому середовищі. Це знижує ризики фінансових втрат від витоків даних, які можуть сягати мільйонів доларів. Напишіть нам — оцінимо ваш проєкт за 1 день.
Чому ізоляція міні-програм — технічний виклик?
У WeChat Mini Programs, Grab SuperApp, Gojek — усюди своя реалізація ізоляції. Головна проблема: нативний код на iOS та Android не вміє «ізолювати» довільний JS або Dart код без спеціальних механізмів. WebView дає ізоляцію DOM, але не ізоляцію пам'яті та не обмеження мережевих запитів.
Типовий антипатерн: завантажити JS міні-програми в WKWebView / WebView, відкрити addJavascriptInterface для потрібних API — і вважати, що це пісочниця. Це не пісочниця. Будь-який XSS у міні-програмі отримує доступ до всіх об'єктів, зареєстрованих через addJavascriptInterface, включаючи мости до нативного коду. Наш досвід показує, що такий підхід призводить до витоків у 9 з 10 аудитів. Вартість впровадження нашої пісочниці окупається за рахунок запобігання подібним інцидентам.
Рівні ізоляції, які ми реалізуємо
Ізоляція виконання коду
На Android міні-програми на JS краще виконувати в окремому процесі через android:process атрибут у маніфесті. Кожна міні-програма — окремий процес зі своєю heap. Креш однієї програми не роняє хост. Для Dart/Flutter — Isolate з обмеженим ReceivePort API.
Для WebView-based міні-програм: WebView з setJavaScriptEnabled(true) в окремому процесі + WebViewClient з білим списком хостів:
class SandboxedWebViewClient(
private val allowedHosts: Set<String>
) : WebViewClient() {
override fun shouldInterceptRequest(
view: WebView,
request: WebResourceRequest
): WebResourceResponse? {
val host = request.url.host ?: return blockRequest()
if (host !in allowedHosts) {
auditLogger.logBlockedRequest(miniProgramId, request.url)
return blockRequest()
}
return null // продолжаем
}
private fun blockRequest() = WebResourceResponse(
"text/plain", "UTF-8", ByteArrayInputStream("blocked".toByteArray())
)
}
JavaScript Bridge з capability model
Замість відкритого addJavascriptInterface — декларативний міст з явним списком дозволів. Міні-програма запитує API, хост перевіряє, чи дозволений він у маніфесті цієї програми:
class CapabilityBridge(
private val miniAppManifest: MiniAppManifest,
private val userId: String
) {
@JavascriptInterface
fun callNative(apiName: String, params: String, callbackId: String) {
val capability = Capability.fromString(apiName) ?: run {
sendError(callbackId, "UNKNOWN_API")
return
}
if (!miniAppManifest.hasPermission(capability)) {
auditLogger.logUnauthorizedApiCall(miniAppId, apiName)
sendError(callbackId, "PERMISSION_DENIED")
return
}
nativeApiRouter.dispatch(capability, params, callbackId)
}
}
Маніфест міні-програми описує запитувані API — аналог uses-permission в Android, тільки для mini app екосистеми.
Ізоляція сховища
Кожна міні-програма отримує ізольований namespace у SharedPreferences та окрему директорію в filesDir:
/app/mini_programs/
/{mini_app_id}/
/storage/ ← SharedPreferences namespace
/files/ ← файлове сховище
/cache/ ← очищається при нестачі місця
Доступ до сховища іншої міні-програми — тільки через явний Intent з підтвердженням користувача. Крос-програмний доступ до даних поза цією схемою — заборонено на рівні ContentProvider з перевіркою callingUid.
Мережева ізоляція
На Android 8+ можна використовувати ConnectivityManager з NetworkCapabilities для прив'язки конкретного з'єднання до VPN-профілю міні-програми. Менш агресивний варіант — proxy з allowlist на рівні хоста та HTTPS pinning до серверів міні-програми через кастомний X509TrustManager. Ми також впроваджуємо моніторинг кількості запитів: ліміт 1000 запитів на хвилину на міні-програму, при перевищенні — блокування з повідомленням.
На iOS — WKContentWorld (iOS 14+) дозволяє виконувати JS кожної міні-програми в ізольованому світі з окремим глобальним об'єктом. Згідно з документацією Apple, це забезпечує повну ізоляцію контекстів виконання.
let miniAppWorld = WKContentWorld.world(withName: "mini_app_\(miniAppId)")
webView.evaluateJavaScript(miniAppCode, in: nil, in: miniAppWorld) { result, error in
// код виконується в ізольованому контексті
}
Різні WKContentWorld не бачать змінні один одного навіть в одному WKWebView.
Як забезпечується довірений запуск?
Перед запуском — верифікація підпису бандла. Кожен бандл підписується розробником і перевіряється за публічним ключем, зареєстрованим на платформі:
fun verifyMiniAppBundle(bundle: ByteArray, signature: ByteArray, publisherKey: PublicKey): Boolean {
val sig = Signature.getInstance("SHA256withECDSA")
sig.initVerify(publisherKey)
sig.update(bundle)
return sig.verify(signature)
}
Запуск непідписаного або модифікованого бандла — відмова з логуванням інциденту.
Приклад із практики
На одному з наших проєктів для фінансового Super App ми виявили, що через відсутність ізоляції міні-програми могли читати дані кредитних карток інших користувачів. Після впровадження повної пісочниці з процесною ізоляцією та capability bridge кількість витоків даних зменшилася до нуля.
Моніторинг під час виконання
Sandbox — не статична конструкція. Потрібен runtime моніторинг: час виконання CPU per міні-програма, об'єм allocated пам'яті, кількість мережевих запитів. Міні-програма, що робить 500 запитів на секунду, або зламана, або займається майнінгом.
На Android — Debug.MemoryInfo + Debug.ThreadCpuTimeNanos() для кожного процесу міні-програми. Пороги налаштовуються в конфігу платформи (наприклад, 200 мс CPU на секунду, 50 МБ пам'яті, 100 мережевих запитів на хвилину).
| Рівень ізоляції | Технологія | Ефект |
|---|---|---|
| Виконання | Окремий процес (android:process) / Isolate | Креш не роняє хост |
| JavaScript міст | CapabilityBridge з маніфестом | Контроль доступу до API |
| Сховище | Namespace + ContentProvider | Ізоляція даних |
| Мережа | WebViewClient allowlist / WKContentWorld | Обмеження запитів |
Процес оцінки та роботи
- Збір вимог та аналіз поточної архітектури.
- Аудит безпеки та виявлення вразливостей.
- Проєктування схеми ізоляції.
- Оцінка обсягу робіт.
- Розробка core-компонентів.
- Тестування пентестами.
- Запуск та підтримка.
Що входить в роботу
- Архітектурна документація схеми ізоляції (процеси, мости, сховище)
- Реалізація core-компонентів: SandboxedWebViewClient, CapabilityBridge, StorageManager
- Інтеграція механізму атестації бандлів з ECDSA-підписами
- Налаштування runtime моніторингу з порогами CPU/пам'ять/мережа
- Аудит безпеки та пентести пісочниці перед запуском
- Підтримка та навчання команди протягом 2 тижнів після впровадження
Строки та вартість
Базова пісочниця з WebView-процесною ізоляцією та capability bridge — 2–3 тижні. Повна платформа з мережевою ізоляцією, атестацією бандлів, runtime моніторингом та консоллю управління дозволами — 2–3 місяці. Вартість розраховується індивідуально після оцінки обсягів. Отримайте консультацію — зв'яжіться з нами для безкоштовного аудиту. Замовте впровадження пісочниці для вашого Super App — ми надамо детальну оцінку.







