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