Как стать автором
Обновить

Шифруем CoreML

Время на прочтение4 мин
Количество просмотров2.4K

ML модели, как и многие другие формы интеллектуальный собственности, подвержены риску быть украденными и использованными без ведома автора. В случае с CoreML большинство моделей зашиты внутри приложения. Достаточно взять Jailbreak девайс, прочитать содержимое бандла и вытащить модель. Подобрать инпут модели уже дело техники и некоторого количества времени. В свое время на практике подобный подход я использовал для сравнения качества нашей ML модели с моделями конкурентов. В этой статье я хотел бы поделиться возможными способами шифрования CoreML моделей.

мое лицо, когда я находил незашифрованную модель
мое лицо, когда я находил незашифрованную модель

В 2020 году Apple представила удобный способ деплоя и шифрования CoreML моделей с помощью Apple Cloud. Это довольно мощный инструмент, который дает нам следующие возможности:

  • Independent development. Возможность обновлять модели на девайсах юзеров без апдейта приложения

  • Model collections. Возможность объединять модели в коллекции и гарантировать их консистентное обновление. Удобно для случая, когда для одной фичи используется несколько моделей.

  • Targeted deployments. Возможность поставлять разные ML модели в зависимости от правил: девайса, версии iOS и т.д.

  • Model encryption. Возможность поставлять модель в зашифрованном виде

Apple Encryption

Остановимся подробней на последнем пункте. Рассмотрим шаги для шифрования ML модели, которую мы будем поставлять вместе с бандлом приложения.

  1. Сначала нам нужно сгенерировать ключ для нашей модели и сохранить его на диске. Для в Project Navigator выбираем нашу модель. Открываем вкладку Utilities и нажимаем Create Encryption Key. В появившемся окне нужно выбрать именно ту команду, под которой мы будем релизить приложение. Нажимаем Continue. Ключ будет сгенерирован и сохранен на диске.

  1. Далее нам нужно указать для Xcode, что мы хотим во время сборки нашего приложения при компиляции модели зашифровать ее с нашим ключом. Для этого выбираем таргет нашего приложения, идем Build Phases ->  Compile Sources и добавляем для нашей модели в Compiler Flags: --encrypt $KeyPathOnDisk.

  1. Готово. Модель зашифрована. Теперь осталось обратиться к ней в коде таким образом, чтобы мы смогли ее дешифровать. Для этого вместо 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 модели с наших серверов. Несколько возможных причин для этого:

  1. Необходимость  более тонкой настройки таргетирования моделей

  2. В компании существует централизованный процесс хранения и апдейта ресурсов приложения, а также требование ему следовать.

  3. A/B тестирование моделей.

  4. Внутренние политики безопасности компании, не позволяющие хранить контент, представляющий интеллектуальную ценность, на серверах Apple.

  5. Поддержка iOS 13 и ниже.

Технически можно пойти по пути, когда мы шифруем модель, чтобы ее забандлить, но по факту не бандлить ее, а доставать зашифрованную, скомпилированную модель и загружать ее на наши сервера. Однако при таком решении, помимо отсутствия возможности автоматизировать процесс деплоя ML модели, значительно повышается риск ошибки, в силу того, что ключ мы будем хранить в Apple Cloud, а саму модель - на наших серверах. 

Давайте рассмотрим возможное решение, если перед нами встала задача кастомного шифрования.

  1. Так как  модель представляет собой папку, поэтому первым шагом, нам нужно ее заархивировать и получить 1 файл. Для этого можно использовать zip, tar или любой другой архиватор.

  2. Далее нам нужно зашифровать наш файл. Для этого можно использовать популярный aes256 либо любой другой алгоритм.

  3. Зашифрованную модель бандлим в приложение или заливаем на бэкенд.

  4. Далее нам нужно придумать способ доставки ключа на клиент. Тут возможны варианты:

    1. Обфусцировать ключ и захардкодить его на клиенте. Обращаться к ключу при этом стоит как можно ближе к моменту расшифровки модели и сразу после этого его релизить, чтобы минимизировать время нахождения целого ключа в памяти. Для обфускации можно воспользоваться

      https://github.com/pjebs/Obfuscator-iOS или https://github.com/UrbanApps/UAObfuscatedString

    2. Можно залить ключ на бэкенд и получать его с помощью запроса в нужный момент.

      [UPD 25.11.22] @house2008сделал хорошее замечание, что для этого метода есть риск того, что на Jailbreak девайсе можно отключить ssl pining и прочитать ключ из ответа бэкенда.

    3. Чтобы максимально усложнить жизнь взломщику можно использовать комбинированный подход и разбить ключ на две части. Одну захардкодить, а другую получать с бэкенда. Опять же важно минимизировать время полного ключа в памяти приложения.

  5. Теперь дешифрование. Во время работы приложения в момент первого обращения к модели за сессию приложения берем зашифрованную модель на диске (предварительно скачиваем если нужно), получаем ключ, дешифруем модель, релизим из памяти ключ, разархивируем модель и сохраняем во временную папку, например:  NSTemporaryDirectory()/YourFolder/

  6. Инициализируем модель и загружаем ее в память c помощью init метода MLModel

  7. Удаляем временную папку.

Конечно это не 100% защита и небольшую часть времени во время работы приложения у нас оказывается на диске незашифрованная модель. Но все же это гораздо лучше, чем не шифровать модель вообще, и усложняет жизнь желающим воспользоваться вашей моделью.

Итого

Мы рассмотрели два подхода к шифрованию CoreML моделей. Какой способ выбрать и стоит ли вообще тратить время на шифрование как водится каждый решает для себя исходя из задач. Всем добра.

Ссылки

Скриншоты взяты из презентации Apple

Теги:
Хабы:
Всего голосов 6: ↑6 и ↓0+6
Комментарии9

Публикации

Истории

Работа

Ближайшие события

27 августа – 7 октября
Премия digital-кейсов «Проксима»
МоскваОнлайн
19 сентября
CDI Conf 2024
Москва
20 – 22 сентября
BCI Hack Moscow
Москва
24 сентября
Конференция Fin.Bot 2024
МоскваОнлайн
25 сентября
Конференция Yandex Scale 2024
МоскваОнлайн
28 – 29 сентября
Конференция E-CODE
МоскваОнлайн
28 сентября – 5 октября
О! Хакатон
Онлайн
30 сентября – 1 октября
Конференция фронтенд-разработчиков FrontendConf 2024
МоскваОнлайн
3 – 18 октября
Kokoc Hackathon 2024
Онлайн