Приносим извинения за кажущуюся очевидность этого вопроса, но по какой-то причине я не смог найти в документации Apple однозначного ответа о том, где и как хранится информация о пароле Settings.bundle. Мой вопрос: если мне нужно сохранить некоторые учетные данные для приложения, и я использую Settings.bundle, чтобы пароль вводился в текстовое поле PSTextFieldSpecifier в области настроек Apple с помощью IsSecure = YES, а затем я получаю доступ к значению из своего приложения, используя CFPreferencesCopyAppValue, никогда не записывать его в NSUserDefaults и только безопасно отправлять по сети, насколько безопасен этот метод хранения и извлечения по сравнению с хранением и извлечением пароля с использованием цепочки для ключей в моих собственных настройках приложения? Спасибо за ваш вклад.
Последствия для безопасности хранения пароля в Settings.bundle и получения с помощью CFPreferencesCopyAppValue
Ответы (3)
CFPreferencesCopyAppValue
— это просто основной способ доступа к той же информации, которую вы получаете при использовании NSUserDefaults
. С точки зрения безопасности, функции точно такие же. То есть он не зашифрован. Он безопасен только в том смысле, что скрыт. «Правильный» ответ — использовать брелок.
Обратной стороной этого является то, что многие приложения используют NSUserDefaults
для хранения паролей. Вы можете возразить, что если пароль не контролирует доступ к любой информации, то попытки использовать связку ключей не стоят усилий. Это подводит меня ко второму аргументу в пользу использования безопасного поля в приложении «Настройки»: API цепочки для ключей ужасен, и, по крайней мере, по моему опыту, написать безошибочный код сложно.
Не сохраняйте пароль пользователя в пакете настроек.
Это небезопасно.
Помните, что вам не нужно знать исходный пароль, вам нужно знать, соответствует ли пароль, который вводит пользователь, исходному паролю. Правильный способ работы с паролями в 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/
Связка ключей на iPhone будет наиболее безопасной, если только вы не используете специальное шифрование, которое очень сложно сделать (и экспортировать). NSUserDefaults не считается безопасным.