我使用crypt()加密我的项目的密码。用户选择密码后,将按以下方式进行加密:
password = crypt(, )
问题是用户使用密码登录时。如果输入的内容与密码不匹配,请检查以下内容:
if (strcmp(crypt(, ), )) { //... }
在某种情况下它不是。假设他们的密码是“ asdf”。如果他们输入带有任何随机结尾字符的“ asdf”,例如“ asdffffff”或“ asdf339sfd”,则该密码仍会接受。似乎忽略了“ asdf”之后的所有内容。
这是隐窝的已知问题吗?还有另一种加密密码的方法吗?
的第二个参数crypt
不应该是用户的帐户名。应该是设置字符串。设置字符串如下所示:
$2b$07$fQuDK3TaQP4sw6IX6iVcTw
该$2b$07$
部分说明了crypt
要使用的密码哈希算法,后面跟随的随机字符字符串是salt。每个用户的盐必须不同,但是不应与用户的帐户名有任何关联。从技术上讲,它不一定是随机的,但是对于每个用户而言,它必须不同,并且每次用户更改密码时都需要更改它,这一点至关重要,因此,最佳实践是使用从加密PRNG中提取的长字符串。
对以前登录的用户进行身份验证时,可以使用存储的哈希密码作为设置字符串:
char *new_hash = crypt("password typed in", "stored hash"); if (new_hash && !strcmp(new_hash, "stored hash")) { // user has successfully logged in }
之所以可行,是因为存储的哈希密码始终总是从最初用于创建它的设置字符串开始,并且crypt
被编码为仅查看设置字符串部分。
(还要注意null检查;某些实现crypt
可能会失败并通过返回null指针来报告失败。)
创建新帐户或更改密码时,必须生成一个新的设置字符串。如果您具有函数crypt_gensalt
,请使用:
char *new_setting = crypt_gensalt("$2b$", 0, 0, 0); if (new_setting) { char *new_hash = crypt("user's new password", new_setting); // ... } else { // halt and catch fire }
crypt_gensalt
不幸的是,如果没有,则必须自己实施。(更糟糕的是,有些Unix具有crypt_gensalt
我上面链接到的文档,而其他Unix具有不同的版本,具有相同的名称,执行相同的工作,但采用不同的论点。该浪费您的Autoconf技能了!)
现在您了解了所有这些,我可以解释为什么
password = crypt("password chosen", "user's account name");
似乎可以正常工作,但是密码被截断了。您的用户帐户名称可能至少以两个字母数字字符开头,对吗?喜欢"Ma[ya]"
,还是"zw[ol]"
?不幸的是,任何两个字母数字字符都构成一个有效的设置字符串...,该字符串选择科学已知的最古老,最不安全的密码哈希算法descrypt之一。(当它在1970年代中期发明时非常好。如今,无论密码是什么,它都可以被蛮力破解。)该算法的许多问题之一是它将所有密码都截断为八字。 asdf
和asdfhjkl
哈希不同的东西,但asdfhjkl
和asdfhjkl1234
哈希同样的事情。
解决方法是使用crypt_gensalt
或等效选择现代算法。所有现代算法都接受任意长的密码短语。