密码验证 - 如何安全地检查输入的密码是否正确

时间:2014-03-21 16:04:09

标签: objective-c security encryption passwords rncryptor

我正在开发一款需要多个密码才能访问不同数据区域的应用。例如,一群人可以设置需要密码身份验证才能查看的聊天。

以下是我正在考虑的方式:

我有我的关键字,假设说:

  

香蕉

当用户输入密码时,我使用RNCryptor使用输入的密钥加密Banana,并将加密的字符串存储到服务器。

稍后,当有人试图输入密码时,我从服务器获取散列值并尝试使用他们输入的密码作为密钥对其进行解密。如果解密的值等于Banana,我知道他们输入了正确的密码。

我是安全新手,所以我不确定这是不是一个合适的解决方案。感谢所有帮助。

更新

在进行了@Greg建议的一些改动以及恰当命名的@ Anti-weakpasswords后,这就是我所拥有的:

- (NSDictionary *) getPasswordDictionaryForPassword:(NSString *)password {

    NSData * salt = [self generateSalt256];
    NSData * key = [RNCryptor keyForPassword:password salt:salt settings:mySettings];

    NSMutableDictionary * passwordDictionary = [NSMutableDictionary new];

    NSString * saltString = stringFromData(salt);
    NSString * keyString = stringFromData(key);

    passwordDictionary[@"key"] = keyString;
    passwordDictionary[@"salt"] = saltString;
    passwordDictionary[@"version"] = @"1.0.0";
    passwordDictionary[@"iterationCount"] = @"10000";

    return passwordDictionary;
}

static const RNCryptorKeyDerivationSettings mySettings = {
    .keySize = kCCKeySizeAES256,
    .saltSize = 32,
    .PBKDFAlgorithm = kCCPBKDF2,
    .PRF = kCCPRFHmacAlgSHA1,
    .rounds = 10000
};

- (NSData *)generateSalt256 {
    unsigned char salt[32];
    for (int i=0; i<32; i++) {
        salt[i] = (unsigned char)arc4random();
    }
    NSData * dataSalt = [NSData dataWithBytes:salt length:sizeof(salt)];
    return dataSalt;
}

2 个答案:

答案 0 :(得分:5)

  • 不要使用任何散列函数的单次传递来存储密码。
  • 请勿在8-16字节范围内使用随机盐。
  • 请勿使用可逆加密来存储密码。
  • 请勿严格按照加密密钥输入密码使用密码。

相反,当用户选择关键字/密码短语

  • 生成加密随机8-16字节盐
  • 将PBKDF2,BCrypt或SCrypt与所述盐一起使用,并使用大型迭代计数/工作因子,因为您的处理器可以处理以创建密码哈希
    • 如果您特定使用PBKDF2,请不要请求比本机散列大小更大的输出(SHA-1 = 20字节,SHA-256为32字节,SHA-384为48字节,SHA-512为64字节) ),或者你增加了攻击者对你的防御者的比较优势。

然后在您的数据库中,您存储该用户的特定内容:

  • 透明的盐
  • 迭代次数/工作系数
    • 因此您可以在以后轻松更改/升级
  • 产生的密码哈希
  • 身份验证协议的版本 - 这可能是2,可能是1。
    • 因此,如果您稍后从此方法迁移到NewWellKnownMethod,您可以轻松地更改/升级

当用户想要对您的系统进行身份验证时,您:

  • 从数据库中检索他们的版本,盐,迭代计数/工作因子以及结果哈希
  • 使用来自数据库的salt和迭代计数/工作因子来输入他们刚刚输入的任何关键字/密码。
  • 将您刚刚获得的结果与数据库中的结果进行比较;如果他们相同,就让他们进去吧。
    • 高级:使用恒定时间比较,因此如果第一个字节不同,它就不会退出尝试,以减少定时攻击的漏洞。

请阅读How to securely hash passwords?,其中Thomas Porrin的答案目前最常被提及Stackexchange密码散列论文,当然是迄今为止我见过的最好的。

答案 1 :(得分:1)

这样做并不好。您应该使用单向散列算法来散列密码(您将无法对其进行解密)。 在您对密码进行哈希处理后,在用户提供密码后将其保存到数据库中,您必须将其哈希并将其(哈希值)与存储在数据库中的哈希进行比较。如果它匹配则意味着如果验证失败则它是相同的。

通过这种方式,即使有人获得对数据库的访问权限,数据也会受到保护,他也不会对此做任何事情,也不会存储密码。

大多数身份验证都是这样做的。

//扩展

你应该使用一些针对这种工作的哈希算法。

结帐SHAMD5