ML модели, как и многие другие формы интеллектуальный собственности, подвержены риску быть украденными и использованными без ведома автора. В случае с CoreML большинство моделей зашиты внутри приложения. Достаточно взять Jailbreak девайс, прочитать содержимое бандла и вытащить модель. Подобрать инпут модели уже дело техники и некоторого количества времени. В свое время на практике подобный подход я использовал для сравнения качества нашей ML модели с моделями конкурентов. В этой статье я хотел бы поделиться возможными способами шифрования CoreML моделей.
В 2020 году Apple представила удобный способ деплоя и шифрования CoreML моделей с помощью Apple Cloud. Это довольно мощный инструмент, который дает нам следующие возможности:
Independent development. Возможность обновлять модели на девайсах юзеров без апдейта приложения
Model collections. Возможность объединять модели в коллекции и гарантировать их консистентное обновление. Удобно для случая, когда для одной фичи используется несколько моделей.
Targeted deployments. Возможность поставлять разные ML модели в зависимости от правил: девайса, версии iOS и т.д.
Model encryption. Возможность поставлять модель в зашифрованном виде
Apple Encryption
Остановимся подробней на последней пункте. Рассмотрим шаги для шифрования ML модели, которую мы будем поставлять вместе с бандлом приложения.
Сначала нам нужно сгенерировать ключ для нашей модели и сохранить его на диске. Для в Project Navigator выбираем нашу модель. Открываем вкладку Utilities и нажимаем Create Encryption Key. В появившемся окне нужно выбрать именно ту команду, под которой мы будем релизить приложение. Нажимаем Continue. Ключ будет сгенерирован и сохранен на диске.
Далее нам нужно указать для Xcode, что мы хотим во время сборки нашего приложения при компиляции модели зашифровать ее с нашим ключом. Для этого выбираем таргет нашего приложения, идем Build Phases -> Compile Sources и добавляем для нашей модели в Compiler Flags:
--encrypt $KeyPathOnDisk
.
Готово. Модель зашифрована. Теперь осталось обратиться к ней в коде таким образом, чтобы мы смогли ее дешифровать. Для этого вместо
init
метода для создания MLModel нужно использовать асинхронный методload
, который появился в iOS 14. Ключ, который мы использовали для шифрования, в момент создания сохраняется в Apple Cloud. В момент первого обращения кload
он скачивается и сохраняется локально на девайсе. Поэтому очень важно, чтобы в момент первого обращения был доступ к сети. При вызовеload
модель дешифруется и загружается в память. На диске же по-прежнему остается зашифрованная ML модель.
MLModel.load(contentsOf: modelURL) { result in
switch result {
case .success(let loadedModel):
print("Successfully loaded model \(loadedModel).")
// Use the loaded model for predictions.
// ...
case .failure(let error):
print("Error loading model: (error).")
}
}
В случае, если мы планируем для доставки модели использовать Apple Cloud, нам нужно выполнить те же шаги, за исключением шага 2. Нам не нужно шифровать модель во время ее компиляции, но нужно во время создания архива. Для этого в диалоговом окне создания архива нам нужно выбрать Encrypt Model и указать путь до нашего ключа
Custom Encryption
Для большинства случаев решение от Apple отлично работает, но бывают исключения, когда приходится задуматься над кастомным решением. Основная причина для этого - кастомный деплой ML моделей, когда нам нужно поставлять ML модели с наших серверов. Несколько возможных причин для этого:
Необходимость более тонкой настройки таргетирования моделей
В компании существует централизованный процесс хранения и апдейта ресурсов приложения, а также требование ему следовать.
A/B тестирование моделей.
Внутренние политики безопасности компании, не позволяющие хранить контент, представляющий интеллектуальную ценность, на серверах Apple.
Поддержка iOS 13 и ниже.
Технически можно пойти по пути, когда мы шифруем модель, чтобы ее забандлить, но по факту не бандлить ее, а доставать зашифрованную, скомпилированную модель и загружать ее на наши сервера. Однако при таком решении, помимо отсутствия возможности автоматизировать процесс деплоя ML модели, значительно повышается риск ошибки, в силу того, что ключ мы будем хранить в Apple Cloud, а саму модель - на наших серверах.
Давайте рассмотрим возможное решение, если перед нами встала задача кастомного шифрования.
Так как модель представляет собой папку, поэтому первым шагом, нам нужно ее заархивировать и получить 1 файл. Для этого можно использовать zip, tar или любой другой архиватор.
Далее нам нужно зашифровать наш файл. Для этого можно использовать популярный
sha256
либо любой другой алгоритм.Ключ и полученный зашифрованный файл заливаем на наш бэкенд.
Далее нам нужно подготовить запрос на бэкенд, с помощью которого мы сможем получать ключ и ссылку на зашифрованной модель.
Во время работы приложения в нужный момент мы отправляем запрос, скачиваем и кешируем на диске зашифрованную модель.
В момент первого обращения к модели за сессию приложения дешифруем ее c помощью полученного ключа, разархивируем и сохраняем во временную папку, например:
NSTemporaryDirectory()/YourFolder/
Инициализируем модель и загружаем ее в память c помощью
init
методаMLModel
Удаляем временную папку.
Конечно это не 100% защита и небольшую часть времени во время работы приложения у нас оказывается на диске незашифрованная модель. Но все же это гораздо лучше, чем не шифровать модель вообще, и усложняет жизнь желающим воспользоваться вашей моделью.
Итого
Мы рассмотрели два подхода к шифрованию CoreML моделей. Какой способ выбрать и стоит ли вообще тратить время на шифрование как водится каждый решает для себя исходя из задач. Всем добра.
Ссылки
Скриншоты взяты из презентации Apple