Реалізація Remote Wipe корпоративних даних у мобільному додатку
Співробітник втратив телефон. У додатку — корпоративна переписка, документи та маркери сеансів. IT-відділ хоче натиснути одну кнопку в консолі та видалити всі корпоративні дані, не зачіпаючи особисті фото. У них є 15 хвилин до того, як телефон потрапить не в ті руки.
Що саме потрібно видалити та як швидко
Remote Wipe — це не одна операція, а каскад. Спочатку потрібно розуміти, що вважається «корпоративними даними»:
- SQLite бази даних та Shared Preferences із маркерами та кешем
- Файли у внутрішньому сховищі (
filesDir,cacheDir) - Дані у Keychain / Android Keystore — сертифікати, ключі шифрування
- Push-маркери FCM/APNs, привʾязані до користувача
- Локальні копії документів у зовнішньому сховищі (якщо є)
- Активні сеанси — вони мають бути інвалідовані на сервері
Файли не можна видалити з диска без команди сервера — пристрій може бути офлайн. Тому потрібна черга команд із гарантованою доставкою.
Архітектура надійного Remote Wipe
Найпоширеніший антипаттерн — реалізувати wipe через звичайний FCM push-маркер. Проблеми: FCM не гарантує доставку, повідомлення може прийти через 6 годин або взагалі не прийти, а на iOS фоновий push не розбудить додаток, якщо його примусово закрив користувач.
Надійна схема виглядає інакше:
-
Сервер позначає пристрій як «підлягає wipe» у БД (прапор
wipe_requested_at) -
З кожним API-запитом сервер повертає
X-Wipe-Required: trueу заголовку (або 403 з кодомWIPE_REQUIRED) - Додаток під час запуску виконує запит перевірки стану та перевіряє цей прапор
- FCM/APNs відправляє команду як додатковий сигнал — не основний
// Interceptor для OkHttp — перевіряємо кожну відповідь
class WipeCheckInterceptor(private val wipeManager: WipeManager) : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val response = chain.proceed(chain.request())
if (response.header("X-Wipe-Required") == "true") {
wipeManager.scheduleImmediateWipe()
}
return response
}
}
Якщо пристрій був офлайн довгий час — при першому ж запиті він отримає команду.
Сам процес видалення
На Android:
class WipeManager(private val context: Context) {
fun performWipe() {
// 1. Інвалідуємо маркери на сервері (fire-and-forget)
authRepository.revokeAllTokens()
// 2. Видаляємо SharedPreferences
context.getSharedPreferences("corp_prefs", Context.MODE_PRIVATE)
.edit().clear().commit() // commit(), не apply() — синхронно
// 3. Видаляємо файли
context.filesDir.deleteRecursively()
context.cacheDir.deleteRecursively()
// 4. Видаляємо ключи з Keystore
val keyStore = KeyStore.getInstance("AndroidKeyStore").apply { load(null) }
keyStore.aliases().toList().filter { it.startsWith("corp_") }.forEach {
keyStore.deleteEntry(it)
}
// 5. Очищаємо базу даних
context.deleteDatabase("corp_database")
// 6. Повідомляємо сервер про успішний wipe
auditRepository.reportWipeCompleted(deviceId)
// 7. Перезапускаємо додаток на екран входу
restartToLoginScreen()
}
}
Важливий момент: apply() у SharedPreferences асинхронний. Якщо після нього додаток упаде — дані можуть залишитися. Використовуйте тільки commit().
На iOS аналогічно, але через UserDefaults.removePersistentDomain() та SecItemDelete() для Keychain:
func performWipe() {
// Keychain
let query: [String: Any] = [kSecClass as String: kSecClassGenericPassword,
kSecAttrService as String: "com.company.corp"]
SecItemDelete(query as CFDictionary)
// UserDefaults
UserDefaults.standard.removePersistentDomain(forName: Bundle.main.bundleIdentifier!)
// Core Data
try? FileManager.default.removeItem(at: coreDataStoreURL)
}
Проблема: wipe під час роботи додатку
Якщо користувач активно працює під час отримання команди — не можна просто видалити базу даних. Спочатку потрібно завершити всі активні транзакції, закрити з'єднання з БД, зупинити фонові роботи (WorkManager.cancelAllWork() на Android, BGTaskScheduler на iOS), й тільки потім видаляти дані.
Без цього на Android 12+ виникає SQLiteDatabaseLockedException, і wipe не завершується повністю.
Аудит виконання
Після кожного wipe сервер має отримати підтвердження з часовою міткою. Якщо підтвердження не прийшло протягом N годин — повторити команду при наступному підключенні. Логи wipe-операцій зберігаються на сервері, не на пристрої.
Терміни
Базова реалізація (без Work Profile, тільки додаток): 2–3 дні. З підтримкою Android Enterprise та інтеграцією в MDM-консоль — від 5 днів.







