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

Log*_*gan 0 security encryption passwords objective-c 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;
}
Run Code Online (Sandbox Code Playgroud)

Ant*_*rds 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和迭代计数/工作因子来输入他们刚刚输入的任何关键字/密码.
  • 将您刚刚获得的结果与数据库中的结果进行比较; 如果他们是相同的,让他们进去.
    • 高级:使用恒定时间比较,因此它不仅仅是在第一个字节不同时退出尝试,以减少定时攻击的漏洞.

请阅读如何安全地散列密码?其中Thomas Porrin的答案是目前最常提到的关于密码散列的Stackexchange论文,当然是迄今为止我见过的最好的.