Хранение конфиденциальной информации

Некоторое время назад мы говорили о сохранении информации в iOS. Есть масса различных способов хранить данные. Однако, есть категория данных, которые необходимо хранить с особой осторожностью. Речь идет о паролях, ключах доступа, финансовой информации и других секретных данных.

Для хранения таких данных также есть несколько подходов.

Первый – шифрование на уровне файловой системы.

Данный способ перекладывает заботу о шифровании критичных данных с разработчика на систему. iOS будет шифровать файлы, выбранные разработчиком в то время, когда устройство заблокировано.

Здесь я лишь хочу упомянуть, что методы сохранения информации могут принимать опции (NSDataWritingOptions). Данными опциями можно указать, что файл должен храниться в зашифрованном виде. Расшифровка файлов будет происходить только, если пользователь разблокировал устройство (можно указать, что пользователю достаточно один раз разблокировать устройство, либо файлы будут вообще недоступны при заблокированом устройстве).
Кроме того, есть метод -setAttributes:ofItemAtPath:error: объекта NSFileManager, в котором можно указать значение атрибута NSFileProtectionKey, который определяет настройки шифрования для файла по указанному пути.

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

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

Этот способ мы рассмотрим подробнее – связка ключей (keychain).

Связка ключей должна быть знакома большинству пользователей Mac. Это системное средство хранения паролей, сертификатов. Аналогичное средство есть и в iOS с некоторыми оговорками. Нет специального приложения для доступа к этой информации, а также – приложения ограничены своими записями в связке ключей (если быть точнее – к записям могут обращаться приложения одного разработчика при правильном указании групп доступа).

Для работы со связкой ключей, необходимо подключить фреймворк Security (это C-фреймворк, используются типы Core Foundation), который определяет четыре функции: SecItemCopyMatching (поиск и чтение данных в связке ключей), SecItemAdd (добавление элемента в связку ключей), SecItemUpdate (обновление элемента в связке ключей), SecItemDelete (удаление элемента из связки ключей).

Код для создания, обновления и удаления элементов можно посмотреть в примере.

Связка ключей оперирует записями (записи могут быть нескольких классов, например, kSecClassGenericPassword). В каждой записи могут быть заданы атрибуты, состав которых зависит от класса записи. В большинстве случаев достаточно будет использовать класс записи kSecClassGenericPassword, и заполнять атрибут kSecAttrService и указывать значение пароля в kSecValueData.
Необходимо отметить, что пароль в связке ключей хранится в виде CFData (CF-аналог класса NSData), поэтому перед сохранением необходимо из строки получить NSData, а при загрузке из связки ключей получить строку.

-(NSData*)dataForString:(NSString*)string
{
    return [string dataUsingEncoding:NSUTF8StringEncoding];
}

-(NSString*)stringForData:(NSData*)data
{
    return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
}

Еще одним важным аспектом работы со связкой ключей является возможность использования значений несколькими приложениями одного разработчика. Для этого необходимо указывать одинаковый параметр kSecAttrAccessGroup при создании элементов в связке ключей в каждом приложении, а также указать эту же accessGroup в секции Keychain Groups в Entitlements каждого из приложений, которое будет использовать эти общие элементы связки ключей.
Приложения с общими Keychain Groups будут иметь возможность обмениваться защищенными данными через связку ключей.
Entitlements - Keychain Groups

Подробный пример работы со связкой ключей приведен Apple.

Упрощенный вариант работы со связкой ключей я выложил на GitHub (он работает только со строками, поддерживает ARC). Можно использовать упрощенную нотацию для словарей.

    SDKeychain *altKeychain = [SDKeychain keychainWithService:@"myService"];

    NSLog(@"value for myKey1 = %@", [SDKeychain defaultKeychain][@"myKey1"]);
    NSLog(@"value for myKey2 = %@", [SDKeychain defaultKeychain][@"myKey2"]);
    NSLog(@"value for myKey2 (in myService) = %@", altKeychain[@"myKey2"]);
    
    [SDKeychain defaultKeychain][@"myKey1"] = @"test";
    altKeychain[@"myKey2"] = @"alt";

    NSLog(@"value for myKey1 = %@", [SDKeychain defaultKeychain][@"myKey1"]);
    NSLog(@"value for myKey2 = %@", [SDKeychain defaultKeychain][@"myKey2"]);
    NSLog(@"value for myKey2 (in myService) = %@", altKeychain[@"myKey2"]);

    [SDKeychain defaultKeychain][@"myKey2"] = @"test2";
    NSLog(@"value for myKey1 = %@", [SDKeychain defaultKeychain][@"myKey1"]);
    NSLog(@"value for myKey2 = %@", [SDKeychain defaultKeychain][@"myKey2"]);
    NSLog(@"value for myKey2 (in myService) = %@", altKeychain[@"myKey2"]);

    [SDKeychain defaultKeychain][@"myKey2"] = @"test2a";
    NSLog(@"value for myKey1 = %@", [SDKeychain defaultKeychain][@"myKey1"]);
    NSLog(@"value for myKey2 = %@", [SDKeychain defaultKeychain][@"myKey2"]);
    NSLog(@"value for myKey2 (in myService) = %@", altKeychain[@"myKey2"]);
    
    [SDKeychain defaultKeychain][@"myKey1"] = nil;
    [SDKeychain defaultKeychain][@"myKey2"] = nil;

Пример можно использовать как есть или слегка доработать напильником для своих нужд.

Как обычно, рекомендую почитать документацию Apple о защите файлов, концепции связки ключей, ключевых моментах использования связки ключей в iOS, описание функций и констант связки ключей.

Примеры работы с Keychain: UICKeyChainStore, GenericKeychain, SecureData.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s