Como o Linux sabe que a nova senha é semelhante à anterior?


145

Algumas vezes tentei alterar uma senha de usuário em várias máquinas Linux e quando a nova senha era semelhante à antiga, o sistema operacional reclamava que eram muito semelhantes.

Eu sempre me perguntei, como o sistema sabe disso? Eu pensei que a senha é salva como um hash. Isso significa que, quando o sistema é capaz de comparar a nova senha por similaridade, a antiga é realmente salva como texto simples?


30
1º off: texto simples? não. Se (!) Salvou, você salva o hash e compara os hashes. No Linux, porém, verifica a senha atual com a nova senha. AMBOS são fornecidos pelo usuário ao alterar senhas.
— Rinzwind

42
@Rinzwind Mas hashes comparando não vai funcionar porque a diferença de um personagem deve resultar em um hash completamente diferente
— slhck

17
Veja também O Facebook armazena senhas em texto simples? no Information Security, por outras maneiras de detectar semelhanças, considerando apenas o hash da senha antiga e o texto sem formatação da nova senha (sem texto sem formatação para a antiga).
— 22414 Bob

21
Você pode testar a similaridade entre uma senha antiga com hash e uma nova senha em texto sem formatação. Simplesmente gere uma lista de senhas semelhante à nova, faça o hash de todas e compare os hashes resultantes com o hash da senha antiga. Se houver correspondência, é semelhante.
— BWG

2
@BWG: Essa é uma pequena simplificação excessiva - os esquemas de hash atuais saltam o hash, então primeiro você precisa extrair o sal do hash da senha antiga e certifique-se de usar esse sal para suas senhas semelhantes às novas. (Estou apontar isto porque é possível que a API não iria expor uma maneira de forçar um sal específico.)
— Ulrich Schwarz

Respostas:


156

Como você precisa fornecer a senha antiga e a nova ao usar passwd, elas podem ser comparadas facilmente em texto sem formatação, na memória, sem gravá-las em algum lugar da unidade.

Na verdade, sua senha é hash quando finalmente é armazenada, mas até que isso aconteça, é claro que a ferramenta em que você digita sua senha pode acessá-la diretamente, como qualquer outro programa pode acessar as coisas que você digitou no teclado enquanto lia o STDIN.

Esse é um recurso do sistema PAM usado em segundo plano da passwdferramenta. O PAM é usado pelas modernas distribuições Linux.

Mais especificamente, pam_cracklibé um módulo para o PAM que permite rejeitar senhas com base em várias fraquezas que as tornariam muito vulneráveis.

Não são apenas as senhas muito semelhantes que podem ser consideradas inseguras. O código fonte possui vários exemplos do que pode ser verificado, por exemplo, se uma senha é um palíndromo ou qual a distância de edição entre duas palavras. A idéia é tornar as senhas mais resistentes a ataques de dicionário.

Veja também a página de pam_cracklibmanual.


você tem idéias em "como" sua explicação se encaixa nos argumentos relatados na minha resposta? Existem duas abordagens diferentes, adotadas pelo aplicativo "passwd", quando o host não reconhece o PAM? PS: Sem críticos. Só estou pensando (como PAM, BTW, foi meu primeiro palpite ... pouco antes de receber o código-fonte).
— Damiano Verzulli

27
Mais perturbadoras são as regras de senha corporativa que alertam se você usou a mesma senha ou uma senha semelhante entre as quatro últimas.
— Nick T

4
@NickT Como isso é (necessariamente) perturbador - eles não poderiam simplesmente salvar seus últimos 4 hashes e comparar cada um deles com o novo proposto da mesma maneira que esta pergunta?
— neminem

1
@neminem "... or similar"
— Nick T

1
@ NickT Ah, é justo, porque neste caso em particular você está comparando com a "senha antiga" inserida pelo usuário para alterar a senha, em vez de com um hash salvo. Ainda assim, você poderia hipoteticamente usar o método BWG publicado em um comentário, para pelo menos verificar alterações realmente simples (uma substituição de caractere, um caractere adicionado / removido, etc.).
— NEMEMEM

46

Pelo menos no meu Ubuntu, as mensagens "muito semelhantes" aparecem when: "... mais da metade dos personagens são diferentes ...." (veja detalhes abaixo). graças ao suporte do PAM, conforme explicado claramente na resposta @slhck.

Para outra plataforma, onde o PAM não é usado, as mensagens "muito semelhantes" são exibidas quando: "... mais da metade dos caracteres são diferentes ..." (veja detalhes abaixo)

Para verificar mais essa declaração por conta própria, é possível verificar o código-fonte. Aqui está como.

O programa "passwd" está incluído no pacote passwd:

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

Como estamos lidando com tecnologias de código aberto, temos acesso irrestrito ao código-fonte. Obtê-lo é tão simples quanto:

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

Posteriormente, é fácil encontrar o fragmento relevante de código:

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

Uma rápida verificação no "obscure.c" fornece isso (estou recortando e colando apenas o trecho 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;
}

Então, agora, sabemos que existe uma função "semelhante" que, com base na verificação antiga e na nova, se ambas são semelhantes. Aqui está o trecho:

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

Eu não revi o código C. Limitei-me a confiar no comentário antes da definição da função :-)


A diferenciação entre plataformas compatíveis com PAM e NON-PAM é definida no arquivo "obscure.c" que está estruturado da seguinte forma:

#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
Essa é uma resposta longa que parece não responder diretamente à pergunta de como ela pode ser comparada à senha antiga quando as senhas são colocadas em hash.
— Jamesdlin

10
@jamesdlin: conforme declarado no comentário de Rinzwind à pergunta original, os hashes NÃO desempenham nenhum papel nesse assunto: quando você executa o comando "passwd" para alterar a senha, é necessário fornecer a senha "antiga" e a "nova". Portanto, o código "passwd" não tem nenhum problema em comparar / verificar a senha de uma só vez (de forma clara; sem hash).
— Damiano Verzulli

3
@DamianoVerzulli No entanto, isso realmente não aborda a questão. A questão não era "qual código C você usa para dizer se duas strings são semelhantes;" isso é exatamente o mesmo para senhas e para qualquer outra coisa. O problema das senhas que as tornam interessantes é que elas nunca são armazenadas em texto simples, e é sobre isso que a pergunta é feita. Isso responde "quais critérios são usados ​​e como é feito em C", mas é muito longo para "quais critérios" e "como eu faria isso em C" é uma questão de SO, não de SU.
— cpast

7
@DamianoVerzulli E o fato de passwdsolicitar senhas antigas e novas é a resposta . O restante desta resposta é irrelevante.
— Jamesdlin # 28/14

3
+1 para uma resposta extremamente relevante e interessante! É bom ver que o código real que compara a senha realmente funciona no texto simples e, como esperado, não no hash.
— Nico

36

A resposta é muito mais simples do que você pensa. De fato, quase se qualifica como mágica, porque depois que você explica o truque, ele desaparece:

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

Password changed successfully

Ele sabe que sua nova senha é semelhante ... Porque você digitou a antiga apenas um momento antes.


2
"... ou doce."
— Nick T

1
Coelho bobo, trix são para crianças!
— iAdjunct

1
O que isso não explica é quando conhece suas n senhas anteriores :) "A senha foi usada muito recentemente", o que impede a troca das mesmas poucas senhas em um ambiente corporativo.
— Juha Untinen

3
@Juha Untinen: Isso é verdade, mas isso pode ser resolvido simplesmente lembrando-se dos últimos N hashes. Capturar "o mesmo que a enésima senha" é fácil, é o " semelhante à enésima senha" que é difícil. Até onde eu saiba, esses sistemas apenas verificam a similaridade com a última senha e a uniformidade com o último N. Se eles verificam a similaridade com o último N ... esse é um truque realmente interessante agora, não é! Não tenho ideia de como eles fariam isso.
— Cort Ammon

7

Embora as outras respostas estejam corretas, vale a pena mencionar que você não precisa fornecer a senha antiga para que isso funcione!

De fato, pode-se gerar um monte de senha semelhante à nova senha fornecida, misturá-los e depois verificar se algum desses hashes corresponde ao antigo. Se for esse o caso, a nova senha será julgada semelhante à antiga! :)


2
Embora esse seja realmente um meio de alcançar esse feito (e seja usado por muitos sites), não é isso que está acontecendo neste caso.
— Brian S

Esse é um truque legal! Um pouquinho mais computacionalmente intensivo, mas inteligente!
— Cort Ammon

Você deve pelo menos fazer uma estimativa de quantas senhas semelhantes precisariam ser geradas para ter uma verificação significativa ou vincular a um recurso externo. Caso contrário, isso é apenas uma idéia de alternativa possível, não uma resposta fundamentada.
— Hyde

@hyde que depende de critérios em que alguém possa pensar. Para mim, as senhas são semelhantes se houver no máximo 3 caracteres adicionados / removidos / modificados. Portanto, são 62 hashes para cada caractere (e se usarmos apenas alfanuméricos) vezes a combinação de 3 do comprimento da senha ( n), que é 62 * (n!)/(6 * (n - 3)!)igual a 13540 para a senha de 12 caracteres. Mas se alguém pensa em algo diferente, a equação é inútil, então por que se preocupar?
— Killah

Resposta estúpida, mas um insight, no entanto. Por que estúpido? 1. Você precisaria gerar um número inimaginável de hashes. 2. Essa configuração enfraqueceria a segurança da senha original. Se alguém obtiver hashes de todas as senhas semelhantes, em vez de apenas uma, eles terão muito mais facilidade para decifrá-las.
— Rok Kralj

5

Um aspecto não foi coberto: histórico de senhas. Alguns sistemas suportam isso. Para fazer isso, ele mantém um histórico de senhas e as criptografa com a senha atual. Quando você altera sua senha, ela usa a senha "antiga" para descriptografar a lista e verificar. E quando define uma nova senha, salva a lista (novamente) criptografada com uma chave derivada da nova senha.

É assim que remember=Nfunciona no PAM (armazenado em /etc/security/opasswd). Mas também o Windows e outros fornecedores de Unix oferecem funções semelhantes.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.