implicações de segurança de armazenar uma senha em Settings.bundle e ficando com CFPreferencesCopyAppValue
-
12-09-2019 - |
Pergunta
Desculpas para a obviedade aparente desta questão, mas por alguma razão eu não tenho sido capaz de encontrar uma resposta definitiva na documentação da Apple sobre onde e como Settings.bundle informações senha é armazenada. A minha pergunta: se eu precisar armazenar algumas credenciais para um aplicativo, e eu uso um Settings.bundle para que a senha é digitada em um campo de texto PSTextFieldSpecifier na área Configurações da Apple com IsSecure = YES, e então eu acessar o valor do meu aplicativo usando CFPreferencesCopyAppValue, não escrevê-lo para fora para NSUserDefaults e enviá-lo somente sobre a rede de forma segura, o quão seguro é que o armazenamento e método de recuperação quando comparado a armazenar e recuperar a senha usando o chaveiro em minhas próprias configurações de aplicativos? Obrigado pela sua entrada.
Solução
CFPreferencesCopyAppValue
é apenas a maneira Núcleo Fundação de acessar a mesma informação que você começa quando usando NSUserDefaults
. Em termos de segurança, as características são exatamente os mesmos. Ou seja, ele não está criptografado. É seguro apenas no sentido de que ele é obscurecida. A resposta "correta" é usar o chaveiro.
O contador para isso é que muitos aplicativos usam NSUserDefaults
para armazenar senhas. Você poderia argumentar que a menos que os controles de senha de acesso à informação de qualquer valor, então não vale a pena o esforço em tentar usar o chaveiro. O que me traz ao segundo argumento em favor do uso de um campo seguro na aplicação Definições:. A API chaveiro é hediondo e, na minha experiência, pelo menos, escrever código livre de erros é complicado
Outras dicas
Não guarde a senha do usuário nas configurações do bundle.
Não é seguro.
Lembre-se, você não precisa saber o que a senha original é, você precisa saber se a senha que o usuário digita jogos a senha original. A maneira correta de lidar com senhas em iOS, quer seja para
- Use o keychain, como outros já referiram
- Gerar uma função hash unidireccional criptográfica usando SHA-512 ou outro criptografia e armazenar o hash resultante e sal em
NSUserDefaults
Destas opções, criptografar a senha e armazenar o hash + sal é de longe o mais fácil. Aqui está o que você faz para armazenar a senha:
- Grab a senha do usuário
- Crie um valor salt aleatório
- Criar um forward-only de hash usando SHA-512 e o valor salt aleatório
- Armazenar o hash resultante eo valor sal em
NSUserDefaults
-. Estes valores não podem ser usados ??por hackers para determinar a senha original, por isso não há necessidade de armazená-los em um lugar seguro
Agora, quando o usuário digita sua senha e você tem que verificar se ele está correto, aqui está o que você faz:
- Grab a senha do usuário
- Grab o valor de hash sal + salvo anteriormente a partir
NSUserDefaults
- Criar um forward-only de hash usando a mesma função hash one-way que você usou para criptografar a senha original - passá-lo a tentativa de senha e o valor sal
NSUserDefaults
- Compare o hash resultante com o que foi armazenado em
NSUSerDefaults
. Se eles são o mesmo, então o usuário digitou a senha correta.
Aqui está o código para gerar o sal eo forward-only de hash:
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];
}
código para este exemplo foi encontrada aqui: http://blog.securemacprogramming.com/2011/04/storing-and-testing-credentials-cocoa-touch-edition/
Keychain no iPhone vai ser o mais seguro, a menos que você estiver usando criptografia de costume, o que é muito difícil de fazer (e exportação). NSUserDefaults não é considerado seguro.