Linux 如何知道新密码与前一个密码相似?

Linux 如何知道新密码与前一个密码相似?

有几次我尝试在各种 Linux 机器上更改用户密码,当新密码与旧密码相似时,操作系统会抱怨它们太相似。

我一直想知道,系统是如何知道这一点的?我以为密码是以哈希值形式保存的。这是否意味着当系统能够比较新密码的相似性时,旧密码实际上以纯文本形式保存?

答案1

由于你需要同时提供旧的使用时输入新密码passwd,可以在内存中以纯文本形式轻松进行比较,而无需将其写入驱动器上的某个位置。

确实,您的密码在最终存储时会被散列,但在此之前,您输入密码的工具当然可以直接访问它,就像任何其他程序在从 STDIN 读取时可以访问您在键盘上输入的内容一样。

这是聚丙烯酰胺系统用于该passwd工具的后台。现代 Linux 发行版都使用 PAM。

更具体地说,pam_cracklib这是一个 PAM 模块,它允许根据一些可能使密码非常脆弱的弱点来拒绝密码。

不仅仅是过于相似的密码才被认为是不安全的。源代码 有各种可以检查的示例,例如密码是否为回文或两个单词之间的编辑距离是多少。这个想法是让密码更能抵御字典攻击。

也可以看看手册pam_cracklib页。

答案2

至少在我的 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 代码。我只能相信函数定义之前的注释 :-)


PAM 和非 PAM 感知平台之间的区别在“obscure.c”文件中定义,其结构如下:

#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 */

答案3

答案比你想象的要简单得多。事实上,它几乎可以算作魔术,因为一旦你解释了这个技巧,它就消失了:

$ passwd
Current Password:
New Password:
Repeat New Password:

Password changed successfully

它知道您的新密码相似...因为您刚刚输入了旧密码。

答案4

有一个方面没有涉及:密码历史记录。有些系统支持此功能。为了做到这一点,它会保留密码历史记录并使用当前密码对其进行加密。当您更改密码时,它会使用“旧”密码解密列表并进行验证。当它设置新密码时,它会(再次)保存使用从新密码派生的密钥加密的列表。

这就是remember=NPAM 的工作方式(存储在 中/etc/security/opasswd)。但 Windows 和其他 Unix 供应商也提供类似的功能。

相关内容