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


145

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

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


30
第一关:纯文字?没有。如果(!)保存,则保存哈希并比较哈希。在Linux中,它会使用新密码检查当前密码。两者均由用户在更改密码时提供。
Rinzwind 2014年

42
@Rinzwind但是比较散列将不起作用,因为一个字符的差异将导致完全不同的哈希
slhck 2014年

17
另请参阅Facebook是否存储纯文本密码?关于信息安全性的其他方法,仅给出了旧密码的哈希值和新密码的明文(对于旧密码则没有明文),以其他方式检测相似性。
鲍勃

21
实际上,您可以测试散列的旧密码和纯文本新密码之间的相似性。只需生成与新密码相似的密码列表,对所有密码进行哈希处理,然后将生成的哈希与旧密码哈希进行比较即可。如果有匹配项,则相似。
BWG 2014年

2
@BWG:这有点过分简化–当前的哈希方案对哈希值加盐,因此首先您要从旧密码哈希值中提取盐值,并确保将盐值用于新密码。(我指出这一点是因为API可能不会公开一种强制使用特定盐的方法。)
Ulrich Schwarz

Answers:


156

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

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

这是工具后台使用的PAM系统的功能passwd。现代Linux发行版使用PAM。

更具体地说,pam_cracklib是用于PAM的模​​块,该模块允许根据一些弱点拒绝密码,这些弱点会使它们非常脆弱。

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

另请参阅pam_cracklib手册页。


您对“如何”解释与我的回答中报告的论点相称有想法吗?当主机不支持 PAM 时,“ passwd”应用程序采用两种不同的方法吗?PS:完全没有批评家。我只是在想(作为PAM,BTW,这是我的第一个猜测……只是在复制源代码之前)。
Damiano Verzulli 2014年

27
更令人不安的是公司密码规则,如果您在过去四个密码中的任何一个中使用相同或相似的密码,就会向您发出警报。
尼克T

4
@NickT(有必要)如何打扰-他们不能只保存您的最后4个哈希,然后以与该问题相同的方式将每个哈希与您提议的新哈希进行比较吗?
neminem 2014年

1
@neminem“ ...或类似”
Nick T

1
@NickT啊,很公平,因为在这种特殊情况下,您要与用户输入的用于更改密码的“旧密码”进行比较,而不是与保存的哈希进行比较。尽管如此,您仍然可以假设使用注释中发布的BWG方法,至少检查真正简单的更改(一个字符替换,一个字符添加/删除等)。
neminem 2014年

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

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

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

9
这是一个很长的答案,似乎并不能直接回答当密码散列时如何将其与旧密码进行比较的问题。
jamesdlin 2014年

10
@jamesdlin:在原来的问题Rinzwind评论指出,哈希也不要玩这方面的任何作用:当你发出了“passwd文件”命令来更改密码,你必须同时提供“老”和“新”的密码。因此,“ passwd”代码在一次比较/检查两个密码(以清晰的形式;根本没有散列)方面根本没有问题。
Damiano Verzulli 2014年

3
@DamianoVerzulli但是,这并不能真正解决问题。问题不是“您使用什么C代码来判断两个字符串是否相似”;密码与其他密码完全相同。关于密码的事情使它们变得有趣,那就是它们从未以明文形式存储,这就是问题所在。这回答了“使用什么标准以及如何在C中完成”,但是对于“什么标准”和“我将如何在C中进行此工作”的时间太长了,这是一个SO问题,而不是SU问题。
cpast 2014年

7
@DamianoVerzulli passwd要求输入新旧密码的事实就是答案。此答案的其余部分无关紧要。
jamesdlin 2014年

3
+1是极为相关且有趣的答案!很高兴看到比较密码的实际代码实际上在纯文本上工作,并且按预期在哈希表上工作。
nico 2014年

36

答案比您想像的要简单得多。实际上,它几乎可以看作是魔术,因为一旦您解释了这个窍门,它就消失了:

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

Password changed successfully

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


2
“……还是糖果。”
尼克T

1
傻兔子,特里克斯是给孩子们的!
iAdjunct

1
它不解释的是什么时候知道您过去的n个密码:)“密码最近使用过”,这可以防止在公司环境中交换相同的几个密码。
Juha Untinen 2014年

3
@Juha Untinen:的确如此,但是只要记住最后的N个哈希即可解决。捕获“与第N个密码相同”很容易,而捕获“与第N个密码类似 ”则很困难。据我所知,这些系统仅检查与最后一个密码的相似性,以及与最后一个N的相似性。如果它们确实检查与最后一个N的相似性,那么这是一个非常有趣的技巧,不是吗!我不知道他们会怎么做。
Cort Ammon 2014年

7

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

实际上,您可以生成一堆类似于您提供的新密码的密码,对它们进行哈希处理,然后检查这些哈希值中的任何一个是否与旧密码匹配。如果是这种情况,则将判断新密码与旧密码相似!:)


2
尽管这确实是实现这一壮举的一种方法(并且被许多网站所使用),但在这种情况下并不是这样。
Brian S

那真是个绝招!一点点的计算强度更高,但是更聪明!
Cort Ammon 2014年

您至少应该估计一下要进行有意义的检查或链接到外部资源,需要生成多少个相似的密码。否则,这仅仅是可能的替代方案的想法,而不是充分的答案。
海德2014年

@hyde取决于某人可能想到的标准。对我来说,如果添加/删除/修改的字符数最多不超过3个,密码也是相似的。因此,每个字符的哈希值是62(并且,如果我们仅使用字母数字n),则是密码长度()乘以3的组合,即62 * (n!)/(6 * (n - 3)!),等于12540个长密码的13540。但是,如果有人想到了不同的东西,那么这个方程是没有用的,那为什么还要麻烦呢?
Killah 2014年

愚蠢的答案,但有见地。为什么傻?1.您将不得不生成无法想象的哈希值。2.这样的设置会削弱原始密码的安全性。如果有人获得了所有相似密码的哈希值,而不仅仅是一个哈希值,那么他们将有更多的时间来破解它。
Rok Kralj 2015年

5

一方面未涵盖:密码历史记录。一些系统支持此功能。为此,它保留了密码的历史记录,并使用当前密码对其进行加密。更改密码时,它将使用“旧”密码来解密列表并进行验证。并且,当设置新密码时,它确实(再次)保存使用从新密码派生的密钥加密的列表。

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.