几次我试图在各种Linux机器上更改用户密码,但是当新密码与旧密码相似时,操作系统抱怨它们太相似了。
我一直想知道,系统如何知道这一点?我以为密码另存为哈希。这是否意味着当系统能够比较新密码的相似性时,旧密码实际上被保存为纯文本吗?
几次我试图在各种Linux机器上更改用户密码,但是当新密码与旧密码相似时,操作系统抱怨它们太相似了。
我一直想知道,系统如何知道这一点?我以为密码另存为哈希。这是否意味着当系统能够比较新密码的相似性时,旧密码实际上被保存为纯文本吗?
Answers:
由于在使用时需要同时提供旧密码和新密码passwd
,因此可以轻松地以明文形式在内存中比较它们,而无需将它们写在驱动器上。
确实,您的密码在最终存储时会被散列,但是在那之前,您输入密码的工具当然可以直接访问它,就像其他程序可以在从STDIN读取内容时访问您在键盘上输入的内容一样。
这是工具后台使用的PAM系统的功能passwd
。现代Linux发行版使用PAM。
更具体地说,pam_cracklib
是用于PAM的模块,该模块允许根据一些弱点拒绝密码,这些弱点会使它们非常脆弱。
不仅密码过于相似,而且可以视为不安全。该源代码 具有什么可以检查各种示例中,例如,密码是否是回文或什么编辑距离是两个单词之间。这样做的目的是使密码更能抵抗字典攻击。
至少在我的Ubuntu中,“太相似”消息出来了 时间:“ ...超过一半的字符是不同的字符...。”(有关详细信息,请参见下文)。 感谢PAM的支持,正如@slhck答案中明确说明的那样。
对于不使用PAM的其他平台,在以下情况下会显示“过于相似”消息:“ ...超过一半的字符是不同的字符...。”(请参见下文以了解详细信息)
要自己进一步检查该语句,可以检查源代码。这是怎么回事。
passwd软件包中包含“ passwd”程序:
verzulli@iMac:~$ which passwd
/usr/bin/passwd
verzulli@iMac:~$ dpkg -S /usr/bin/passwd
passwd: /usr/bin/passwd
在处理开源技术时,我们可以不受限制地访问源代码。获得它很简单:
verzulli@iMac:/usr/local/src/passwd$ apt-get source passwd
之后,很容易找到相关的代码片段:
verzulli@iMac:/usr/local/src/passwd$ grep -i -r 'too similar' .
[...]
./shadow-4.1.5.1/NEWS:- new password is not "too similar" if it is long enough
./shadow-4.1.5.1/libmisc/obscure.c: msg = _("too similar");
快速检查一下“ obscure.c”就可以了(我只剪切并粘贴了相关的代码):
static const char *password_check (
const char *old,
const char *new,
const struct passwd *pwdp)
{
const char *msg = NULL;
char *oldmono, *newmono, *wrapped;
if (strcmp (new, old) == 0) {
return _("no change");
}
[...]
if (palindrome (oldmono, newmono)) {
msg = _("a palindrome");
} else if (strcmp (oldmono, newmono) == 0) {
msg = _("case changes only");
} else if (similar (oldmono, newmono)) {
msg = _("too similar");
} else if (simple (old, new)) {
msg = _("too simple");
} else if (strstr (wrapped, newmono) != NULL) {
msg = _("rotated");
} else {
}
[...]
return msg;
}
因此,现在,我们知道有一个“相似”功能,该功能基于旧的和新的检查两者是否相似。这是代码段:
/*
* more than half of the characters are different ones.
*/
static bool similar (const char *old, const char *new)
{
int i, j;
/*
* XXX - sometimes this fails when changing from a simple password
* to a really long one (MD5). For now, I just return success if
* the new password is long enough. Please feel free to suggest
* something better... --marekm
*/
if (strlen (new) >= 8) {
return false;
}
for (i = j = 0; ('\0' != new[i]) && ('\0' != old[i]); i++) {
if (strchr (new, old[i]) != NULL) {
j++;
}
}
if (i >= j * 2) {
return false;
}
return true;
}
我还没有审查过C代码。我限制了我对函数定义之前的注释的信任:-)
在“ obscure.c”文件中定义了PAM和NON-PAM感知平台之间的区别,其结构如下:
#include <config.h>
#ifndef USE_PAM
[...lots of things, including all the above...]
#else /* !USE_PAM */
extern int errno; /* warning: ANSI C forbids an empty source file */
#endif /* !USE_PAM */
passwd
要求输入新旧密码的事实就是答案。此答案的其余部分无关紧要。
答案比您想像的要简单得多。实际上,它几乎可以看作是魔术,因为一旦您解释了这个窍门,它就消失了:
$ passwd
Current Password:
New Password:
Repeat New Password:
Password changed successfully
它知道您的新密码是相似的...因为您刚刚输入了旧密码。
尽管其他答案是正确的,但值得一提的是您无需提供旧密码即可使用!
实际上,您可以生成一堆类似于您提供的新密码的密码,对它们进行哈希处理,然后检查这些哈希值中的任何一个是否与旧密码匹配。如果是这种情况,则将判断新密码与旧密码相似!:)
n
),则是密码长度()乘以3的组合,即62 * (n!)/(6 * (n - 3)!)
,等于12540个长密码的13540。但是,如果有人想到了不同的东西,那么这个方程是没有用的,那为什么还要麻烦呢?