Linux 如何知道新密码与之前的密码相似?

ps-*_*aux 146 linux security unix

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

我一直在想,系统怎么知道这个?我认为密码保存为哈希。这是否意味着当系统能够比较新密码的相似性时,旧密码实际上被保存为纯文本?

slh*_*hck 155

由于您在使用时需要同时提供旧密码新密码passwd,因此可以在内存中以明文形式轻松比较它们,而无需将它们写在驱动器的某处。

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

这是在工具后台使用的PAM 系统的一个特性passwd。现代 Linux 发行版使用 PAM。

更具体地说,它pam_cracklib是一个 PAM 模块,它允许基于几个使密码非常脆弱的弱点拒绝密码。

不仅仅是太相似的密码可以被认为是不安全的。该源代码 具有什么可以检查各种示例中,例如,密码是否是回文或什么编辑距离是两个单词之间。这个想法是使密码更能抵抗字典攻击。

另请参阅pam_cracklib手册页。

  • 更令人不安的是公司密码规则会提醒您是否在最后四个密码中使用了相同或相似的密码。 (28认同)
  • @NickT 这(必然)如何令人不安-他们不能只保存您的最后 4 个哈希值,然后以与此问题相同的方式将每个哈希值与您提出的新哈希值进行比较吗? (4认同)
  • @neminem“...或类似的” (2认同)

Dam*_*lli 46

至少在我的 Ubuntu 中,出现了“太相似”的消息 当:“......超过一半的字符是不同的......”(详情见下文)。 感谢 PAM 的支持,正如@slhck 的回答中清楚地解释的那样。

对于其他不使用 PAM 的平台,在以下情况下会出现“太相似”消息:“......超过一半的字符是不同的......”(详情见下文)

要自己进一步检查此语句,可以检查源代码。这是如何。

“passwd”程序包含在 passwd 包中:

verzulli@iMac:~$ which passwd
/usr/bin/passwd
verzulli@iMac:~$ dpkg -S /usr/bin/passwd
passwd: /usr/bin/passwd
Run Code Online (Sandbox Code Playgroud)

当我们处理开源技术时,我们可以不受限制地访问源代码。获取它很简单:

verzulli@iMac:/usr/local/src/passwd$ apt-get source passwd
Run Code Online (Sandbox Code Playgroud)

之后很容易找到相关的代码片段:

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");
Run Code Online (Sandbox Code Playgroud)

快速检查“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;
}
Run Code Online (Sandbox Code Playgroud)

所以,现在,我们知道有一个“相似”的函数,它基于旧函数和新函数来检查两者是否相似。这是片段:

/*
 * 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;
}
Run Code Online (Sandbox Code Playgroud)

我还没有查看 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 */
Run Code Online (Sandbox Code Playgroud)

  • @jamesdlin :正如 Rinzwind 对原始问题的评论中所述,哈希在这件事中 ** 不** 发挥任何作用:当您发出“passwd”命令来更改密码时,您需要同时提供“旧”和“新密码。因此,“passwd”代码在一次比较/检查两个密码时完全没有问题(以清晰的形式;根本没有散列)。 (10认同)
  • 这是一个很长的答案,似乎并没有直接回答当密码被散列时它如何与旧密码进行比较的问题。 (9认同)
  • @DamianoVerzulli 事实上,`passwd` 要求​​提供旧密码和新密码*就是答案*。这个答案的其余部分无关紧要。 (7认同)
  • @DamianoVerzulli 尽管如此,这并没有真正解决问题。问题不是“你用什么 C 代码来判断两个字符串是否相似;” 这对于密码和其他任何东西都是一样的。_passwords_ 的有趣之处在于它们从未以明文形式存储,这就是问题所要问的。这回答了“使用什么标准以及它是如何在 C 中完成的”,但是对于“什么标准”和“我将如何在 C 中做到这一点”来说太长了,这是一个 SO 问题,而不是 SU 问题。 (3认同)
  • +1 非常相关和有趣的答案!很高兴看到比较密码的实际代码实际上适用于明文,正如预期的那样,不适用于散列。 (3认同)
  • @jamesdlin 源代码是明文比较答案的证明。其他答案只是猜测,它必须以这种方式完成。之后,将给出确切相似之处的解释作为进一步信息。在这里,我们从不鼓励进一步的信息。这个答案的不足之处在于它没有说明这一点。 (3认同)
  • @cpast 看问题标题:“Linux 怎么知道新密码和之前的相似?” - 回答,通过在这些特定的方式_检查旧的和新的。这绝对可以回答这个问题,并且比大多数其他答案更好 (2认同)

Cor*_*mon 36

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

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

Password changed successfully
Run Code Online (Sandbox Code Playgroud)

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

  • @Juha Untinen:这是真的,但可以通过简单地记住最后 N 个哈希来处理。捕获“与第 N 个密码相同”很容易,而“*与第 N 个密码相似*”则很难。据我所知,这些系统只检查与最后一个密码的相似性,以及与最后 N 个密码的相似性。如果它们确实检查与最后 N 个密码的相似性……现在这是一个非常有趣的技巧,不是吗!我不知道他们会怎么做。 (3认同)
  • “……或者糖果。” (2认同)

Ant*_*Ant 7

尽管其他答案是正确的,但值得一提的是,您无需提供旧密码即可正常工作!

事实上,可以生成一堆类似于您提供的新密码的密码,对它们进行散列,然后检查这些散列中的任何一个是否与旧的相匹配。如果是这样,那么判断新密码与旧密码相似!:)

  • 虽然这确实是实现这一壮举的一种手段(并且被许多网站使用),但在本例中并非如此。 (2认同)

eck*_*kes 5

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

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