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?

Arkonix
fonte
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.

slhck
fonte
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 */
Damiano Verzulli
fonte
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.

Cort Ammon
fonte
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! :)

Formiga
fonte
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.

eckes
fonte