Последствия безопасности для хранения пароля в Settings.bundle и получение с помощью CFPreferencesCopyAppValue

Извините за кажущуюся очевидность этого вопроса, но по какой-то причине я не смог найти окончательный ответ в документации Apple о том, где и как хранится информация о пароле Settings.bundle. Мой вопрос: если мне нужно сохранить некоторые учетные данные для приложения, и я использую параметр Settings.bundle, чтобы пароль был введен в текстовое поле PSTextFieldSpecifier в области настроек Apple с помощью IsSecure = YES, а затем я получаю доступ к значению из своего приложения, используя CFPreferencesCopyAppValue, никогда не записывая его в NSUserDefaults и надежно отправляя его по сети, насколько безопасен этот метод хранения и извлечения по сравнению с хранением и извлечением пароля с помощью keychain в настройках моего собственного приложения? Спасибо за ваш вклад.

Ответ 1

CFPreferencesCopyAppValue - это просто основной способ доступа к той же информации, которую вы получаете при использовании NSUserDefaults. С точки зрения безопасности, функции точно такие же. То есть, он не зашифрован. Он защищен только в том смысле, что он затенен. "Правильный" ответ - использовать брелок.

Считаем, что многие приложения используют NSUserDefaults для хранения паролей. Вы можете утверждать, что, если пароль не контролирует доступ к информации любой ценности, тогда это не стоит усилий по попытке использовать цепочку ключей. Это приводит ко второму аргументу в пользу использования безопасного поля в приложении "Настройки": API-интерфейс для ключей является отвратительным, и, по моему опыту, писать код без ошибок сложно.

Ответ 2

Не сохраняйте пароль пользователя в наборе параметров.
Это не безопасно.

Помните, что вам не нужно знать, что такое оригинальный пароль, вам нужно знать, вводит ли пароль пользовательский пароль. Правильный способ обработки паролей в iOS - либо

  • Используйте цепочку ключей, как упомянули другие
  • Создание криптографической односторонней хеш-функции с использованием SHA-512 или другого шифрования и сохранение полученного хеша и соли в NSUserDefaults

Из этих параметров шифрование пароля и сохранение хэш + соли на сегодняшний день является самым простым. Вот что вы делаете, чтобы сохранить пароль:

  • Получить пароль от пользователя
  • Создать значение случайной соли.
  • Создать хеш-форвард только с использованием SHA-512 и значения случайной соли.
  • Сохранять полученное значение хэша и соли в NSUserDefaults - эти значения не могут использоваться хакерами для определения исходного пароля, поэтому нет необходимости хранить их в безопасном месте.

Теперь, когда пользователь вводит свой пароль, и вы должны проверить, правильно ли это, вот что вы делаете:

  • Получить пароль от пользователя
  • Возьмите ранее сохраненное значение хэша + соль из NSUserDefaults
  • Создайте хэширование только вперед, используя одну и ту же одностороннюю хеш-функцию, которую вы использовали для шифрования исходного пароля - передав ему попытку пароля и значение соли из NSUserDefaults
  • Сравните полученный хэш с тем, который был сохранен в NSUserDefaults. Если они совпадают, пользователь вводит правильный пароль.

Здесь код для генерации соли и только хеш-форвард:

NSString *FZARandomSalt(void) {
    uint8_t bytes[16] = {0};
    int status = SecRandomCopyBytes(kSecRandomDefault, 16, bytes);
    if (status == -1) {
        NSLog(@"Error using randomization services: %s", strerror(errno));
        return nil;
    }
    NSString *salt = [NSString stringWithFormat: @"%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
                      bytes[0],  bytes[1],  bytes[2],  bytes[3],
                      bytes[4],  bytes[5],  bytes[6],  bytes[7],
                      bytes[8],  bytes[9],  bytes[10], bytes[11],
                      bytes[12], bytes[13], bytes[14], bytes[15]];
    return salt;
}

NSData *FZAHashPassword(NSString *password, NSString *salt) {
    NSCParameterAssert([salt length] >= 32);
    uint8_t hashBuffer[64] = {0};
    NSString *saltedPassword = [[salt substringToIndex: 32] stringByAppendingString: password];
    const char *passwordBytes = [saltedPassword cStringUsingEncoding: NSUTF8StringEncoding];
    NSUInteger length = [saltedPassword lengthOfBytesUsingEncoding: NSUTF8StringEncoding];
    CC_SHA512(passwordBytes, length, hashBuffer);
    for (NSInteger i = 0; i < 4999; i++) {
        CC_SHA512(hashBuffer, 64, hashBuffer);
    }
    return [NSData dataWithBytes: hashBuffer length: 64];
}

Код для этого примера был найден здесь: http://blog.securemacprogramming.com/2011/04/storing-and-testing-credentials-cocoa-touch-edition/

Ответ 3

Брелок на iPhone будет самым безопасным, если вы не используете пользовательское шифрование, что очень сложно сделать (и экспортировать). NSUserDefaults не считается безопасным.