Подтвердить что ты не робот

Как безопасно включать секретный ключ/подпись в приложениях iOS/Cocoa

Я хочу включить секретный ключ в приложение iOS, чтобы приложение могло "доказать" определенному серверу, что запрос поступает из самого приложения, а не какой-либо другой системы. Я знаю, что просто жесткая кодировка секретного ключа в самом коде очень уязвима, поскольку любой может сделать джейлбрейк своего телефона и подключить GDB к моему приложению, чтобы получить ключ. Есть ли более безопасные способы сделать это? Возможно ли достаточно запутать ключ, чтобы сделать это почти невозможным?

Я считаю, что это аналогичная проблема для проверки серийного номера. К сожалению, это, кажется, треснуло регулярно и легко. Есть ли какие-либо решения для этого?

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

Спасибо, М

4b9b3361

Ответ 1

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

Ответ 2

Я тоже размышлял об этом, и на ум приходят несколько потенциальных решений, основанных на предпосылке, что вам нужно получить секретный ключ пользователя/пароля в ваше приложение KeyChain (которое довольно надежно защищено iOS и оборудованием) и потяните его для использования по мере необходимости:

  1. Распространите секрет в своем приложении, используя специфичный для приложения iCloud ubiquity-container. эти данные должны быть исключены из резервной копии на локальный компьютер и предположительно надежно переданы с использованием защиты на аппаратном уровне только не взломанным приложениям. Плюсы: его нет в вашем приложении при первоначальном распространении, поэтому его сложнее раскрыть, iCloud требует не взломанного устройства, вы можете обновить свой секрет, и он будет синхронизироваться со всеми вашими приложениями. "против": это не совсем в безопасном KeyChain, что означает, что он может быть обнаружен в файловой системе, если iCloud синхронизируется, а затем устройство взломано.

  2. доставьте секрет своему приложению в виде бесплатного контента, размещенного в магазине приложений. когда оно доставлено (надежно в магазине приложений, только на не взломанные устройства) приложению, передайте его в связку ключей. Плюсы: его нет в вашем приложении при первоначальном распространении, поэтому его сложнее обнаружить, для магазина приложений требуется не взломанное устройство. "против": сложнее быстро изменить секрет для всех ваших установок, даже для бесплатной покупки в магазине приложений может потребоваться аутентификация пользователя, что затрудняет работу UX.

Идеальным решением было бы, если бы мы могли каким-то образом связать секреты (словарь ключ/значение KeyChain) прямо в приложение, когда мы отправляем его для распространения, магазин приложений удалил бы их и надежно доставил бы их в ОС для инъекции в KeyChain во время установить, но вне диапазона от обычного пакета приложений, синхронизированного с вашим настольным компьютером и iTunes, и они не будут отображаться в двоичных файлах. Если бы Apple не добавила такую функцию, я думаю, что нет действительно надежного решения.

Ответ 3

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

Этот вопрос содержит один подход к скрытию секретного ключа в двоичном коде.

Не предполагайте, что с помощью https вы не можете обманывать пакеты. Что делать, если злоумышленник изменил свои URL-адреса внутри вашего исполняемого файла, чтобы указать на свой сервер? Тогда они могут действовать как реле.

Лучшим способом было бы обеспечить некоторое управление идентификацией внутри приложения (пользователь выбирает имя пользователя, пароль генерируется пользователем/машиной) и использует эти учетные данные для ваших вызовов службы.

Ответ 4

Я согласен с @Nubis, что нет 100% пуленепробиваемого способа сделать это.

Однако эта библиотека кажется прагматичным решением проблемы:

https://github.com/UrbanApps/UAObfuscatedString

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

Ответ 5

Как обновление ответа @natbro, отличным решением является использование CloudKit. С помощью этого метода вы создадите запись в публичной базе данных, и каждый экземпляр приложения получит ее при запуске. Поскольку CloudKit основан на входе в систему iCloud, он обладает большинством, если не всеми, тех же мер безопасности, которые будут иметь специфичные для приложения iCloud ubiquity-container. Есть два основных различия:

  1. CloudKit более детерминирован, когда дело доходит до получения данных. Вы знаете, что секреты/ключи будут доступны, когда вы получите их из CloudKit.

  2. Данные из CloudKit не синхронизируются с устройством и не кэшируются в контейнере приложения, они извлекаются по требованию, и любое кэширование остается за вами, разработчик (примечание: я бы предложил кэшировать ключи в цепочке для ключей).

Вот быстрый фрагмент для извлечения записи из CloudKit.

import CloudKit

...

let publicCloudKitDatabase = CKContainer.default().publicCloudDatabase
let recordID = CKRecord.ID(recordName: "default") // or whatever you name it

publicCloudKitDatabase.fetch(withRecordID: recordID) { (record, error) in
    if let secretRecord = record {
        guard let secret = secretRecord["aKey"] as? String else {
            print("Unable to get secret")
            return
        }

        self.secret = secret // or somesuch
    }
}

Примечания. Вам необходимо настроить CloudKit, как указано в документации, а затем создать запись, соответствующую ожидаемому приложению, или наоборот (в этом случае запись с recordName = "default", которая содержит поле с ключом " ключ").

Ответ 6

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

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

Ответ 7

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