139

Несколько раз я пытался изменить пароль пользователя на разных машинах Linux, и когда новый пароль был похож на старый, ОС жаловалась, что они слишком похожи.

Я всегда задавался вопросом, как система узнает об этом? Я думал, что пароль сохраняется как хеш. Означает ли это, что когда система может сравнивать новый пароль на предмет сходства, старый пароль фактически сохраняется в виде простого текста?

5 ответов5

155

Поскольку при использовании passwd указывать как старый, так и новый пароль, их можно легко сравнить в открытом тексте, в памяти, не записывая их где-либо на диске.

Действительно, ваш пароль хэшируется, когда он наконец сохраняется, но пока это не произойдет, инструмент, в котором вы вводите свой пароль, может, конечно, просто получить к нему доступ напрямую, как любая другая программа, может получить доступ к вещам, которые вы вводили на клавиатуре, когда он читал из STDIN.

Это особенность системы PAM, которая используется в качестве фона инструмента passwd . PAM используется в современных дистрибутивах Linux.

В частности, pam_cracklib - это модуль для PAM, который позволяет отклонять пароли на основании нескольких недостатков, которые делают их очень уязвимыми.

Не только пароли, которые слишком похожи, могут считаться небезопасными. Исходный код содержит различные примеры того, что можно проверить, например, является ли пароль палиндромом или каково расстояние редактирования между двумя словами. Идея состоит в том, чтобы сделать пароли более устойчивыми к атакам по словарю.

Смотрите также справочную страницу pam_cracklib .

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 Я ограничил себя в доверии к комментарию как раз перед определением функции :-)


Различие между платформами, поддерживающими PAM и NON-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 */
37

Ответ гораздо проще, чем вы думаете. На самом деле, это почти квалифицируется как магия, потому что как только вы объясните хитрость, она исчезнет:

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

Password changed successfully

Он знает, что ваш новый пароль похож ... Потому что ты набрал старый всего за минуту до этого.

8

Хотя другие ответы верны, стоит упомянуть, что вам не нужно указывать старый пароль, чтобы это работало!

Фактически, можно создать группу паролей, аналогичную введенному вами новому паролю, хэшировать их, а затем проверить, совпадает ли какой-либо из этих хэшей со старым. Если это так, то новый пароль оценивается как старый! :)

4

Один аспект не был покрыт: история паролей. Некоторые системы поддерживают это. Для этого он хранит историю паролей и шифрует их с помощью текущего пароля. Когда вы меняете свой пароль, он использует "старый" пароль для расшифровки списка и проверки. И когда он устанавливает новый пароль, он сохраняет список (снова) зашифрованный ключом, полученным из нового пароля.

Вот как remember=N работает в PAM (хранится в /etc/security/opasswd). Но также Windows и другие поставщики Unix предлагают аналогичные функции.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .