¿Cómo sabe Linux que la nueva contraseña es similar a la anterior?

145

Algunas veces intenté cambiar una contraseña de usuario en varias máquinas Linux y cuando la nueva contraseña era similar a la anterior, el sistema operativo se quejó de que eran demasiado similares.

Siempre me pregunté, ¿cómo sabe esto el sistema? Pensé que la contraseña se guarda como un hash. ¿Significa esto que cuando el sistema puede comparar la nueva contraseña por similitud, la antigua realmente se guarda como texto sin formato?

Arkonix
fuente
30
Primero apagado: texto sin formato? No. Si (!) Guardado, guarda el hash y compara los hash. En Linux, aunque comprueba la contraseña actual con una nueva contraseña. AMBOS son proporcionados por el usuario al cambiar las contraseñas.
Rinzwind
42
@Rinzwind Pero comparar hashes no funcionará porque una diferencia de un carácter debería dar como resultado un hash completamente diferente
slhck
17
Consulte también ¿Facebook almacena contraseñas de texto sin formato? en Seguridad de la información para otras formas de detectar similitudes dado solo el hash de la contraseña anterior y el texto sin formato de la nueva contraseña (sin texto sin formato para los antiguos).
Bob
21
En realidad, puede probar la similitud entre una contraseña antigua con hash y una contraseña nueva de texto sin formato. Simplemente genere una lista de contraseñas similares a la nueva, escríbalas todas y compare los hash resultantes con el hash de contraseña anterior. Si alguna coincidencia, entonces es similar.
BWG
2
@BWG: Esa es una ligera simplificación excesiva: los esquemas de hash actuales sacan el hash, por lo que primero debe extraer la sal del hash de contraseña anterior y asegurarse de usar esa sal para sus contraseñas similares a las nuevas. (Estoy señalando esto porque es posible que la API no exponga una forma de forzar una sal específica).
Ulrich Schwarz

Respuestas:

156

Dado que debe proporcionar tanto la contraseña antigua como la nueva cuando se usa passwd, se pueden comparar fácilmente en texto sin formato, en memoria, sin escribirlas en algún lugar de la unidad.

De hecho, su contraseña se codifica cuando finalmente se almacena, pero hasta que eso suceda, la herramienta donde está ingresando su contraseña puede, por supuesto, acceder directamente como cualquier otro programa puede acceder a las cosas que ingresó en su teclado mientras leía desde STDIN.

Esta es una característica del sistema PAM que se utiliza en el fondo de la passwdherramienta. PAM es utilizado por las distribuciones modernas de Linux.

Más específicamente, pam_cracklibes un módulo para PAM que permite rechazar contraseñas basadas en varias debilidades que las harían muy vulnerables.

No solo las contraseñas que son demasiado similares pueden considerarse inseguras. El código fuente tiene varios ejemplos de lo que se puede verificar, por ejemplo, si una contraseña es un palíndromo o cuál es la distancia de edición entre dos palabras. La idea es hacer que las contraseñas sean más resistentes a los ataques de diccionario.

Ver también la página de pam_cracklibmanual.

slhck
fuente
¿Tiene ideas sobre "cómo" su explicación encaja con los argumentos que se informan en mi respuesta? ¿Existen dos enfoques diferentes, tomados por la aplicación "passwd", cuando el host no es compatible con PAM? PD: No hay críticas en absoluto. Me pregunto (como PAM, por cierto, fue mi primera suposición ... justo antes de agarrar el código fuente).
Damiano Verzulli
27
Más inquietantes son las reglas de contraseña corporativa que lo alertan si ha usado la misma contraseña o una similar entre cualquiera de las últimas cuatro.
Nick T
44
@NickT ¿Cómo es eso (necesariamente) perturbador? ¿No podrían simplemente guardar sus últimos 4 hashes y luego comparar cada uno de ellos con el nuevo propuesto de la misma manera que esta pregunta?
neminem
1
@neminem "... o similar"
Nick T
1
@NickT Ah, es justo, porque en este caso particular se compara con la "contraseña anterior" que ingresa el usuario para cambiar la contraseña, en lugar de con un hash guardado. Aún así, podría usar hipotéticamente el método BWG publicado en un comentario, para al menos verificar cambios realmente simples (una sustitución de caracteres, un carácter agregado / eliminado, etc.).
neminem
46

Al menos en mi Ubuntu, los mensajes "demasiado similares" aparecen cuando: "... más de la mitad de los personajes son diferentes ..." (ver más abajo para más detalles). gracias al soporte de PAM, como se explica claramente en la respuesta @slhck.

Para otra plataforma, donde no se utiliza PAM, los mensajes "demasiado similares" aparecen cuando: "... más de la mitad de los caracteres son diferentes ..." (ver más abajo para más detalles)

Para verificar esta declaración por su cuenta, es posible verificar el código fuente. Aquí es cómo.

El programa "passwd" está incluido en el paquete passwd:

verzulli@iMac:~$ which passwd
/usr/bin/passwd
verzulli@iMac:~$ dpkg -S /usr/bin/passwd
passwd: /usr/bin/passwd

Como estamos tratando con tecnologías de código abierto, tenemos acceso ilimitado al código fuente. Conseguirlo es tan simple como:

verzulli@iMac:/usr/local/src/passwd$ apt-get source passwd

Después es fácil encontrar el fragmento de código relevante:

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");

Una comprobación rápida de "obscure.c" muestra esto (estoy cortando y pegando solo el fragmento de código relevante):

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;
}

Entonces, ahora, sabemos que hay una función "similar" que se basa en el antiguo y el nuevo para verificar si ambos son similares. Aquí está el fragmento:

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

No he revisado el código C. Me limité a confiar en el comentario justo antes de la definición de la función :-)


La diferenciación entre las plataformas con reconocimiento PAM y NO PAM se define en el archivo "obscure.c" que está estructurado de la siguiente manera:

#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 */
revs Damiano Verzulli
fuente
99
Esta es una respuesta larga que no parece responder directamente a la pregunta de cómo se puede comparar con la contraseña anterior cuando las contraseñas están en hash.
jamesdlin
10
@jamesdlin: como se indicó en el comentario de Rinzwind a la pregunta original, los hashes NO juegan ningún papel en este asunto: cuando emite el comando "passwd" para cambiar la contraseña, debe proporcionar tanto la contraseña "antigua" como la "nueva". Por lo tanto, el código "passwd" no tiene ningún problema en comparar / verificar ambas contraseñas a la vez (en formas claras; no hash en absoluto).
Damiano Verzulli
3
@DamianoVerzulli Sin embargo, esto realmente no aborda la cuestión. La pregunta no era "¿qué código C usas para saber si dos cadenas son similares?" eso es exactamente lo mismo para las contraseñas que para cualquier otra cosa. Lo que pasa con las contraseñas que las hace interesantes es que nunca se almacenan en texto sin formato, y de eso se trata la pregunta. Esto responde "qué criterios se usan y cómo se hace en C", pero es demasiado largo para "qué criterios" y "cómo haría esto en C" es una pregunta SO, no una pregunta SU.
cpast
77
@DamianoVerzulli Y el hecho de que passwdpida contraseñas antiguas y nuevas es la respuesta . El resto de esta respuesta es irrelevante.
jamesdlin
3
¡+1 para una respuesta extremadamente relevante e interesante! Es agradable ver que la contraseña de comparación de código real realmente funciona en el texto sin formato y, como se esperaba, no en el hash.
nico
36

La respuesta es mucho más simple de lo que piensas. De hecho, casi califica como magia, porque una vez que explicas el truco, desaparece:

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

Password changed successfully

Sabe que tu nueva contraseña es similar ... Porque escribiste la anterior solo un momento antes.

Cort Ammon
fuente
2
"... o dulces".
Nick T
1
¡Conejo tonto, trix son para niños!
iAdjunct
1
Lo que no explica es cuando conoce tus n contraseñas pasadas :) "La contraseña se ha usado demasiado recientemente", lo que evita el intercambio de las mismas contraseñas en un entorno corporativo.
Juha Untinen
3
@Juha Untinen: Eso es cierto, pero eso se puede manejar simplemente recordando los últimos N hashes. Capturar "igual que la enésima contraseña" es fácil, es la " contraseña similar a la enésima" que es difícil. Hasta donde sé, estos sistemas solo verifican la similitud con la última contraseña y la similitud con la última N. Si comprueban la similitud con la última N ... ese es un truco realmente interesante ahora, ¿no? No tengo idea de cómo harían eso.
Cort Ammon
7

Aunque las otras respuestas son correctas, vale la pena mencionar que no necesita proporcionar la contraseña anterior para que esto funcione.

De hecho, uno puede generar un montón de contraseñas similares a la nueva contraseña que proporcionó, aplicarles un hash y luego verificar si alguno de estos hashes coincide con el anterior. Si este es el caso, ¡la nueva contraseña se considera similar a la anterior! :)

Hormiga
fuente
2
Si bien este es un medio para lograr esta hazaña (y es utilizado por muchos sitios web), eso no es lo que está sucediendo en este caso.
Brian S
Ese es un buen truco! Un poquito más computacionalmente intensivo, ¡pero inteligente!
Cort Ammon
Al menos debe dar una estimación de cuántas contraseñas similares deberían generarse para tener una verificación significativa o un enlace a un recurso externo. De lo contrario, esto es solo una idea de una posible alternativa, no una respuesta justificada.
hyde
@hyde que depende de criterios que alguien pueda pensar. Para mí, las contraseñas son similares si se agregaron / eliminaron / modificaron un máximo de 3 caracteres. Entonces, son 62 hashes para cada carácter (y eso si solo usamos alfanuméricos) por la combinación de 3 de la longitud de la contraseña ( n), que es 62 * (n!)/(6 * (n - 3)!)igual a 13540 para una contraseña de 12 caracteres. Pero si alguien piensa en algo diferente, la ecuación es inútil, entonces, ¿por qué molestarse?
Killah
Estúpida respuesta, pero una idea sin embargo. ¿Por qué estúpido? 1. Tendrías que generar un número inimaginable de hashes. 2. Tal configuración debilitaría la seguridad de la contraseña original. Si alguien obtuviera hashes de todas las contraseñas similares en lugar de un solo hash, tendrían mucho más tiempo para descifrarlo.
Rok Kralj
5

Un aspecto no estaba cubierto: el historial de contraseñas. Algunos sistemas lo admiten. Para hacerlo, mantiene un historial de contraseñas y las cifra con la contraseña actual. Cuando cambia su contraseña, utiliza la contraseña "antigua" para descifrar la lista y verificar. Y cuando establece una nueva contraseña, guarda la lista (nuevamente) encriptada con una clave derivada de la nueva contraseña.

Así es como remember=Nfunciona en PAM (almacenado en /etc/security/opasswd). Pero también Windows y otros proveedores de Unix ofrecen funciones similares.

Eckes
fuente