Привет, Хабр! Пишу от лица Мастерской IT.ru по запросу команды MyBox и ее лидера Вовы. Ребята столкнулись с задачей, которая тяжко решается - так что предлагаем ее спецам с Хабра за, естественно, награду. Подарим Mac Mini на 1 ТБ SSD за успешное решение.
Что за задача?
Есть проект MyBox - защищенное персональное хранилище на базе Apple Mac mini. Устройство должно уметь предоставить удалённому узлу подписанный Apple «аттестат», подтверждающий, что на устройстве запущено приложение с конкретным хешем бинарника.
Условия (жесткие):
SIP включен
Приватные API не используем
Понижать защиту macOS нельзя
"Аттестация" проходит через сеть, внутри одной машины проблем нет
Зовем такие задачи ТРИЗками - в честь теории решения изобретательских задач. Тут реально нужно поломать голову, как обойти системные ограничения.
Что уже пробовали и отбросили в команде MyBox:
Apple API — нет публичных методов для сторонних разработчиков.
Приватные API — требуют отключения SIP.
DeviceCheck/AppAttest — либо не работают на macOS, либо не дают нужной привязки к хешу бинарника.
Что нужно на выходе:
Рабочее решение с инструкцией по воспроизведению. Либо теоретическое, если команда MyBox сможет его реализовать на практике. Кто пришлет первым валидный вариант - получает MyBox на базе Apple Mac Mini с 1 ТБ SSD. Если Mac Mini не нужен - подберем альтернативу той же ценности, не вопрос.
Кого ищем?
Системных программистов, понимающих устройство macOS.
Реверс-инженеров, которые не боятся внутрянки Mac.
Безопасников, знающих цепочки доверия Apple.
Как участвовать:
Пишите решение в комментариях здесь или в тг. Можно ссылку на решение, главное - чтобы можно было проверить и повторить.
Ждем ваши варианты! Бонус: что уже накидали в пути решения - можно почитать в комментариях под постом. Подключайтесь к обсуждению!
Комментарии (6)

novoselov
05.03.2026 11:52App Attest + Notarization Ticket + SecCode API
1. DCAppAttestService (macOS 14+)
Публичный API, не требует отключения SIP. Привязывает ключ в Secure Enclave к конкретному App ID (Team ID + Bundle ID) и выдаёт сертификатную цепочку, подписанную Apple
let service = DCAppAttestService.shared let keyId = try await service.generateKey() let attestation = try await service.attestKey(keyId, clientDataHash: SHA256(challenge))2. Notarization Ticket как доказательство хеша бинарника
При нотаризации Apple выдаёт тикет, который:
криптографически подписан Apple,
содержит cdHash нотаризованного бинарника,
стаплируется в bundle (
xcrun stapler staple).
Тикет можно извлечь из bundle и отправить удалённой стороне, она верифицирует подпись Apple и извлекает хеш. Публичный ключ Apple для проверки тикетов встроен в macOS и задокументирован. Notarization Ticket нужно уметь парсить (формат Apple Binary Property List внутри
.dmg-style структуры). Формат не документирован официально, но хорошо изучен если поискать.3. SecCode API для получения cdHash запущенного процесса
var code: SecCode? SecCodeCopySelf([], &code) // code текущего процесса var info: CFDictionary? SecCodeCopySigningInformation(code as! SecStaticCode, SecCSFlags(rawValue: kSecCSSigningInformation), &info) let cdHash = (info as! [String: Any])[kSecCodeInfoCdHash as String] // cdHash — SHA-1 или SHA-256 кодовой подписи, тот же, что в notarization ticketЭто системный вызов, а не self-report приложения - ядро macOS возвращает данные из code signature structure, и подделать их без отключения SIP нельзя
Вся цепочка выглядит как-то так
[Remote Server] [MyBox App] | | |-- 1. challenge_nonce --------------->| | | | 2. attestKey(keyId, SHA256(nonce)) | → Apple attestation cert chain | | | 3. SecCodeCopySelf → cdHash | Extract notarization ticket from bundle | | | 4. payload = {nonce, cdHash, ticket, timestamp} | assertion = generateAssertion(keyId, SHA256(payload)) | | |<-- 5. {attestation, payload, assertion}--| | | 6. Verify attestation chain (Apple CA) | 7. Verify assertion signature (attested pubkey) | 8. Verify notarization ticket (Apple signature) | 9. ticket.cdHash == payload.cdHash == expected_hash

Shaman_RSHU
05.03.2026 11:52Удалённую аттестацию приложения на macOS можно попытаться собрать из стандартных механизмов системы, не отключая SIP и не используя приватные API.
Идея такая - связать Secure Enclave, cdHash запущенного бинарника, Apple notarization ticket и nonce сервера. Устройство подписывает эти данные ключом из Secure Enclave, сервер проверяет подпись, ticket Apple и совпадение хеша бинарника.Общая схема
Нужно доказать серверу три факта:
сообщение подписано реальным устройством
подпись относится к конкретному запуску приложения
бинарник соответствует нотариализованной версии Apple
Для этого используются четыре элемента:
ключ устройства в Secure Enclave
cdHash запущенного приложения
notarization ticket Apple
nonce, присланный сервером
1. Ключ устройства (Secure Enclave)
При первом запуске приложение создаёт ключ ECDSA P-256 внутри Secure Enclave.
Через:
Security.frameworkили
DeviceCheck / App Attest
Ключ:
неэкспортируемый
привязан к устройству
используется только для подписи
Серверу отправляется только публичный ключ.
2. Получение хеша запущенного приложения
В рантайме приложение может получить собственный cdHash (CodeDirectory hash) через публичный
SecCodeAPI.var code: SecCode? SecCodeCopySelf([], &code) var info: CFDictionary? SecCodeCopySigningInformation(code!, SecCSFlags(kSecCSSigningInformation), &info) let dict = info as! [String: Any] let cdHashes = dict[kSecCodeInfoCdHashes as String] as! [Data] let cdHash = cdHashes.first!Это тот же хеш, который macOS использует при проверке подписи приложения.
3. Подтверждение Apple (notarization)
Бинарник проходит обычную цепочку:
codesign notarization staplerПосле этого внутри
.appпоявляется notarization ticket, подписанный Apple и содержащий cdHash.Проверка локально:
xcrun stapler validate MyBox.app4. Протокол аттестации
Сервер отправляет устройству случайный challenge:
nonceПриложение формирует payload:
payload = nonce || cdHash || ticket || timestampИ подписывает его ключом Secure Enclave:
signature = ECDSA_sign(payload)Ответ серверу:
{ "payload": "...", "signature": "...", "cdHash": "...", "ticket": "...", "devicePublicKey": "..." }5. Проверка на сервере
Сервер выполняет три проверки.
1. Ticket Apple
проверяется подпись Apple
извлекается cdHash
2. Совпадение хеша
cdHash_ticket == cdHash_client3. Подпись устройства
Verify(devicePublicKey, payload, signature)Также проверяются nonce и timestamp (защита от replay).
Результат
Если все проверки проходят, сервер знает:
сообщение подписано Secure Enclave конкретного Mac
подпись относится к реальному запуску приложения
бинарник соответствует нотариализованной версии Apple
Ограничение
Нужен Secure Enclave - старые Intel-Mac без T2 такой сценарий не поддерживают.

Shaman_RSHU
05.03.2026 11:52Но эта реализация подвержена следующим рискам ИБ:
Реализация даёт гарантию - сервер может быть уверен, что:
подпись сделана ключом Secure Enclave;
бинарник соответствует нотариализованной версии;
сообщение свежее.
Но не может на 100% доказать, что:
код не модифицирован в памяти;
нет инжектированного кода;
устройство — настоящий Mac;
клиент не проксируется.
MinimumLaw
А вариант exec(sha256sum argv[0]) с перехватом stdout в таком варианте не прокатит? Как самый простой вариант?
И да - реализовывать лень, да и не на чем. Очень уж задачка "для плохих собеседований", если такой алгоритм устроит.
AnnaKononova Автор
Ответ от лида продукта: у удаленного узла нет гарантии, что он общается именно с нужным ему процессом и что он не был подменен кем-либо