Привет, Хабр! Пишу от лица Мастерской 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)


  1. MinimumLaw
    05.03.2026 11:52

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

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


    1. AnnaKononova Автор
      05.03.2026 11:52

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


  1. novoselov
    05.03.2026 11:52

    App 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


  1. 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) через публичный SecCode API.

    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.app
    

    4. Протокол аттестации

    Сервер отправляет устройству случайный 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_client
    

    3. Подпись устройства

    Verify(devicePublicKey, payload, signature)
    

    Также проверяются nonce и timestamp (защита от replay).

    Результат

    Если все проверки проходят, сервер знает:

    • сообщение подписано Secure Enclave конкретного Mac

    • подпись относится к реальному запуску приложения

    • бинарник соответствует нотариализованной версии Apple

    Ограничение

    Нужен Secure Enclave - старые Intel-Mac без T2 такой сценарий не поддерживают.


    1. Shaman_RSHU
      05.03.2026 11:52

      Но эта реализация подвержена следующим рискам ИБ:

      Реализация даёт гарантию - сервер может быть уверен, что:

      • подпись сделана ключом Secure Enclave;

      • бинарник соответствует нотариализованной версии;

      • сообщение свежее.

      Но не может на 100% доказать, что:

      • код не модифицирован в памяти;

      • нет инжектированного кода;

      • устройство — настоящий Mac;

      • клиент не проксируется.


      1. vindy
        05.03.2026 11:52

        у вас внутри совсем-совсем ничего не протестует, когда вы копипастите ИИ слоп?