Всем привет! Подытоживаю поиски решения, которые команда стартапа MyBox из Мастерской IT.ru вела с участием Хабра и независимых сообществ.

Задача от лидера продукта Вовы была такая: нужно заставить macOS предоставить удалённому узлу (через сеть, внутри одной машины проблем нет) подписанный Apple «аттестат», подтверждающий, что на устройстве запущено приложение с конкретным хешем бинарника. При этом macOS должна работать в режиме полной безопасности (SIP включён, приватные API не используются, понижение защиты не допускается). Детальнее в прошлой статье: https://habr.com/ru/articles/1006814/.

Накопили мешок не сработавших идей, собрали аргументацию от профи, почему рабочего решения не существует, и главное - пришли к гипотезе альтернативного архитектурного решения для продукта.

Задачка до выхода на публику

Есть проект MyBox - защищенное персональное хранилище на базе Apple Mac mini. Устройство (бокс) должно уметь предоставить удалённому узлу подписанный Apple «аттестат», подтверждающий, что на устройстве запущено приложение с конкретным хешем бинарника. 

Это нужно для тиражирования технологии: бокс каким-то образом устанавливает себя на другой Mac mini. Например, исходный MyBox подключается к новому MacMini через shared disk (из recovery режима), можно другим способом (например, установив какое-то приложение, в том числе из Appstore). 

Жесткие условия:

  • SIP включен

  • Приватные API не ��спользуем

  • Понижать защиту macOS нельзя

  • "Аттестация" проходит через сеть, внутри одной машины проблем нет

Что пробовали и отбросили внутри команды MyBox:

  • Apple API — нет публичных методов для сторонних разработчиков.

  • Приватные API — требуют отключения SIP.

  • DeviceCheck/AppAttest — либо не работают на macOS, либо не дают нужной привязки к хешу бинарника.

Это решение было условием быстрого, удобного и безопасного перехода продукта из состояния “собрали штучные вручную” в более воспроизводимую версию. Команда продукта решила вынести задачку на публичное обсуждение с призовым фондом: вдруг найдутся эксперты и решат за пару дней вместо нескольких недель. 

Задачку закинули в ТГ-канал, Сетку, не совсем разрешенный Линкедин и на Хабр, а также понесли по знакомым и чатикам проф. сообществ.

Рекомендации решений

Комментарии были разные, от откровенно странных до глубоко технических и крутых. Делимся выжимкой.

1. Hierachical deterministic дерево одноразовых ключей шифрования, адресация на ts + SHA256 и все пакеты разных пользователей в одном открытом хранилище

Ответ команды: это решение не по условиям, заданным в ТРИЗке, увы.

2. exec(sha256sum argv[0]) с перехватом stdout — как самый простой вариант?

Ответ: у удалённого узла нет гарантии, что он общается именно с нужным процессом и что он не был подменен.

3. App Attest + Notarization Ticket + SecCode API

Автор расписал целую схему: DCAppAttestService (macOS 14+), нотаризационный тикет, SecCode API для получения cdHash запущенного процесса. Все красиво, с кодом, с пояснениями. Это был первый ответ, который действительно мог бы оказаться решением, спасибо автору за попытку.

Ответ команды после проверки на устройствах: направление мысли интересное, но DCAppAttestService гарантированно не доступен на macOS (DCAppAttestService.isSupported возвращает false).

4. Верификация через бэкенд: прописывать версию приложения в базе и сверять при логине

Ответ: это предложение про пересмотр условий задачи, не подходит под наши жесткие требования.

5. Google Santa (и его форк northpolesec/santa)

Ответ: там про запуск на локальной машине - это мы и так умеем.

6. Эмулятор мака, который легально устанавливается и позволяет исполнять любые бинарники без проверки аттестатов

Ответ: а кто проверит подлинность самого эмулятора? Переносим проблему на другой уровень.

Подтверждение: решения нет

Несколько спецов, задав дополнительные вопросы, дружно написали: публичного API для такого на macOS нет. В качестве примера - самый полный ответ, почему у задачи нет решения:

App Attest на Mac официально не поддерживается (DCAppAttestService.isSupported возвращает false), а Managed Device Attestation/ACME аттестует только устройство и свойства платформы (версию ОС, SIP, Secure Boot, привязку ключа к Secure Enclave), но не конкретный пользовательский процесс и не хеш его бинарника. Code signing и notarization позволяют лишь локально проверить, что bundle не подменен, но не выдать удалённому узлу Apple-подписанное доказательство именно с этим бинарём.

Спасибо прокомментировавшим так и разобравшим в деталях: вы подтвердили, что мы ничего не пропустили и картина такая, какая есть. Встал вопрос: как минимально изменить задачу для успешного решения?

Альтернативные пути с минимальными уступками

Один из комментаторов предложил переформулировать: не требовать Apple-signed attestation конкретного приложения, а оставить Apple только как источник доверия к устройству и hardware-bound ключу. Схема такая:

  • Apple/MDM аттестует сам Mac и его security posture (SIP, Secure Boot, привязку ключа к Secure Enclave).

  • На устройстве есть неэкспортируемый ключ из Secure Enclave.

  • Приложение по challenge от сервера локально проверяет собственную подпись, свой cdhash, после чего подписывает nonce этим ключом.

  • Сервер проверяет, что перед ним действительно доверенный Mac, что ответ подписан hardware-bound ключом именно этого Mac, и что приложение заявило разрешенный cdhash.

То есть Apple аттестует устройство, а приложение аттестует само себя поверх этого.

Проблема этого подхода: разработчик с доступом к Apple Developer Account может выпустить «злое» приложение с тем же teamId.appId, которое будет иметь доступ к Secure Enclave, и, зная целевой cdhash, сможет сэмулировать ожидаемый ответ. Мы вернулись к исходной уязвимости.

Но обсуждение пошло дальше. Другой комментатор предложил ослабить задачу до continuity: на первом запуске маленький доверенный helper создает неэкспортируемый ключ в Secure Enclave, сервер запоминает только публичную часть, и дальше все сессии идут через challenge/response этим ключом. Это убирает простое клонирование на другой Mac, но не доказывает, что самый первый запуск был именно официальной сборкой. Приводим этот комментарий с продолжением:

Практический минимум для production это оставить этот ключ, но перенести доверие в release-процесс: helper/daemon подписывает и нотаризует только CI/HSM или cloud-managed Developer ID, доступ к кл��чу helper’а ограничивается code-signing requirement’ом/keychain ACL, при желании даже exact cdhash, а helper локально проверяет main app по DR/cdhash/notarization ticket и подписывает серверу измерение приложения. Тогда устройства вообще не надо “подписывать вручную”: каждое само генерирует свой device key, а вы централизуете только release-signing; и именно тут решается сценарий “разработчик с доступом к аккаунту выпустил backdoor”, потому что Apple отдельно подчёркивает, что подпись от вашего имени возможна для любого, у кого есть доступ к Developer ID identity, тогда как cloud signing/cloud-managed Developer ID позволяет убрать приватный ключ с рабочих машин.

Если нужен ещё и Apple-rooted сигнал о самом Mac без ручной возни с устройствами, то минимально добавляется: Apple Business Manager/Automated Device Enrollment --> MDM --> ACME/Managed Device Attestation. Это уже даёт zero-touch enrolment, Apple-подписанную аттестацию устройства с freshness nonce и привязкой attested key к конкретному Secure Enclave, а на Apple silicon Mac с macOS 14+ ещё и аттестацию SIP и Secure Boot; для уже купленных Mac их можно разово завести в ABM через Apple Configurator, после чего они ведут себя как обычные managed-устройства. Но даже в этой схеме Apple всё равно аттестует устройство, а не hash вашего процесса, так что app-level часть по‑прежнему остаётся за вашим helper’ом и release-политикой.

По этому комментарию у команды состоялся созвон. При предложенном решении у нас остались следующие варианты:

• создавать все устройства в контролируемой среде (т.е. по сути перенос доверия на «компанию»), но это противоречит цели, т.к. это нельзя проверить и что «компания» вложит при создании каждого устройства - вопрос, это не получится вынести на кибериспытания.

• если брать MDM - это снова централизация, т.е. точкой коррупции становится тот кто управляет тем что ставится через MDM.

Новая гипотеза вместо решения

Наша исходная гипотеза была такой:

  • Первое устройство-родоначальник создаём в контролируемой среде (с участием экспертов, публично, с артефактами ключевых проверок и кибериспытаниями).

  • Последующие устройства должны сами себя «создавать» по образу и подобию первого.

Комментарии и собственное исследование показали: так сделать нельзя в рамках нашей архитектуры.

Но из предложения ослабить задачу до continuity и последующего обсуждения родилась новая гипотеза: MDM прямо на первом устройстве. Ход мысли такой:

  • MDM - это централизация, но точкой коррупции становится тот, кто управляет тем, что ставится через MDM.

  • А что, если поднять MDM-сервис на самом «первом» устройстве, чтобы он был его неотъемлемой частью?

  • Тогда это устройство гарантированно работает на подлинном железе и может проходить кибериспытания.

  • А все последующие устройства получают доверие через него, не требуя от Apple невозможного.

Гуглили опенсорс MDM решения прямо на созвоне. 

Сейчас команда ушла в изучение возможностей MDM-управления с прицелом на то, чтобы подтвердить: даже имея доступ к MDM, мы не можем навредить пользователю или получить его данные. Если гипотеза подтвердится, это станет нашим архитектурным решением для этой версии продукта.

Вместо заключения

Огромное спасибо всем, кто писал комментарии - от предложения идей на подумать до глубоких технических разборов. Вы не только сэкономили нам кучу времени, доказав, что решение в лоб невозможно, но и помогли переформулировать задачу!

Иногда самый ценный результат поиска - не найденное решение, а груз с плеч, тяжесть с сердца и арсенал бронебойных аргументов, почему у нас не вышло пойти запланированным маршрутом.

Если у вас есть мысли про MDM на первом устройстве или вы видите другие пути - милости просим в комментарии. Если хотите следить за новостями MyBox или новыми задачками - в наш тг-канал тоже можно заглядывать.

П.С. Важно: мы не упоминали имена, ники, ссылки, адреса почт и прочие личные данные, т.к. не собирали на это согласия отвечавших. Если вы автор ценных мыслей из статьи и хотите об этом заявить - напишите в комментарии, мы немедленно подтвердим и еще раз выразим огромное спасибо от лица команды!