Pergunta

No momento, estamos armazenando senhas em texto simples para um aplicativo da web que temos.

Eu continuo defendendo a mudança para um hash de senha, mas outro desenvolvedor disse que isso seria menos seguro - mais senhas poderiam corresponder ao hash e um ataque de dicionário/hash seria mais rápido.

Existe alguma verdade neste argumento?

Foi útil?

Solução

Absolutamente nenhum.Mas isso não importa.Já postei uma resposta semelhante antes:

É lamentável, mas as pessoas, até mesmo os programadores, são emocionais demais para serem facilmente influenciadas por argumentos.Uma vez que ele tenha investido em sua posição (e, se você está postando aqui, ele está), você provavelmente não conseguirá convencê-lo apenas com fatos.O que você precisa fazer é inverter o ônus da prova.Você precisa fazer com que ele procure dados que ele espera que o convençam e, ao fazê-lo, aprenda a verdade.Infelizmente, ele tem o benefício do status quo, então você terá um caminho difícil até lá.

Outras dicas

De Wikipédia

Alguns sistemas de computadores armazenam senhas de usuário, contra as quais comparar as tentativas de login do usuário, como ClearText.Se um invasor obtiver acesso a um armazenamento de senha interno, todas as senhas e todas as contas de usuário serão comprometidas.Se alguns usuários empregarem a mesma senha para contas em sistemas diferentes, eles também serão comprometidos.

Os sistemas mais seguros armazenam cada senha em um formulário criptograficamente protegido; portanto, o acesso à senha real ainda será difícil para um snopador que obtém acesso interno ao sistema, enquanto a validação das tentativas de acesso ao usuário permanece possível.

Uma abordagem comum armazena apenas uma forma "hashed" da senha de texto simples.Quando um usuário digita uma senha nesse sistema, o software de manuseio de senha é executado através de um algoritmo de hash criptográfico e se o valor de hash gerado a partir da entrada do usuário corresponde ao hash armazenado no banco de dados de senha, o usuário é permitido acesso.O valor do hash é criado aplicando uma função de hash criptográfica a uma sequência que consiste na senha enviada e, geralmente, outro valor conhecido como sal.O sal impede que os atacantes construam uma lista de valores de hash para senhas comuns.MD5 e SHA1 são frequentemente usados ​​funções de hash criptográfico.

Há muito mais que você pode ler sobre o assunto nessa página.Na minha opinião, e em tudo que li e trabalhei, o hash é um cenário melhor, a menos que você use um algoritmo muito pequeno (<256 bits).

Não há absolutamente nenhuma desculpa para manter senhas de texto simples no aplicativo da web.Use um algoritmo de hash padrão (SHA-1, não MD5!) com um valor salt, para que ataques de arco-íris sejam impossíveis.

Não entendo como seus outros desenvolvedores dizem que 'mais senhas podem corresponder ao hash'.

Há argumentos para que um 'ataque de hash seria mais rápido', mas apenas se você não estiver salgando as senhas à medida que elas são criptografadas.Normalmente, as funções de hash permitem fornecer um sal que torna o uso de uma tabela de hash conhecida uma perda de tempo.

Pessoalmente, eu diria 'não'.Com base no que foi dito acima, bem como no fato de que, se você de alguma forma conseguir expor o texto não criptografado, um valor com hash salgado terá pouco valor para alguém que está tentando entrar.O hash também oferece o benefício de fazer com que todas as senhas 'pareçam' do mesmo tamanho.

ou seja, se o hash de qualquer string sempre resultar em um hash de 20 caracteres, então, se você tiver apenas o hash para ver, não poderá dizer se a senha original tinha oito ou dezesseis caracteres, por exemplo.

Encontrei exatamente esse mesmo problema em meu local de trabalho.O que fiz para convencê-lo de que o hash era mais seguro foi escrever uma injeção SQL que retornasse a lista de usuários e senhas da seção pública do nosso site.Foi escalado imediatamente como um grande problema de segurança :)

Para evitar ataques de dicionário/hash, certifique-se de fazer hash em um token que seja exclusivo para cada usuário e estático (nome de usuário/data de adesão/guid do usuário funciona bem)

Se você não salgar sua senha, você será suspeito de ataques Rainbow Table (dicionários pré-compilados que possuem entradas válidas para um determinado hash)

O outro desenvolvedor deveria parar de falar sobre segurança se você estiver armazenando senhas em texto simples e começar a ler sobre segurança.

Colisões são possíveis, mas geralmente não são um grande problema para aplicativos de senha (elas são principalmente um problema em áreas onde hashes são usados ​​como forma de verificar a integridade dos arquivos).

Então:Salgue suas senhas (adicionando Salt ao lado direito da senha*) e use um bom algoritmo de hashing como SHA-1 ou preferencialmente SHA-256 ou SHA-512.

PS:Um pouco mais de detalhes sobre Hashes aqui.

* Não tenho certeza se o Salt deve ou não estar no início ou no final da string.O problema é que se você tiver colisões (duas entradas com o mesmo hash), adicionar o Salt ao lado "errado" não alterará o hash resultante.De qualquer forma, você não terá grandes problemas com Rainbow Tables, apenas com colisões

Há um velho ditado sobre programadores que fingem ser criptógrafos :)

Jeff Atwood tem um bom post sobre o assunto: Você provavelmente está armazenando senhas incorretamente

Para responder de forma mais ampla, concordo com tudo o que foi dito acima, o hash facilita em teoria para obter a senha do usuário, pois várias senhas correspondem ao mesmo hash.No entanto, é muito menos provável que isso aconteça do que alguém obtendo acesso ao seu banco de dados.

É verdade que se você fizer hash de algo, sim, haverá colisões, então seria possível que duas senhas diferentes desbloqueassem a mesma conta.

Do ponto de vista prático, porém, esse é um argumento ruim - uma boa função de hashing (md5 ou sha1 seria bom) pode garantir que para todas as strings significativas, especialmente as curtas, não haverá colisões.Mesmo que houvesse, ter duas senhas correspondentes para uma conta não é um grande problema - se alguém estiver em posição de adivinhar senhas aleatoriamente com rapidez suficiente para conseguir entrar, você terá problemas maiores.

Eu diria que armazenar as senhas em texto simples representa um risco de segurança muito maior do que colisões de hash na correspondência de senhas.

Não sou especialista em segurança, mas tenho a sensação de que, se o texto simples fosse mais seguro, o hash não existiria.

Em teoria, sim.As senhas podem ser mais longas (mais informações) que um hash, portanto existe a possibilidade de colisões de hash.No entanto, a maioria dos ataques é baseada em dicionário e a probabilidade de colisões é infinitamente menor do que uma correspondência direta bem-sucedida.

Depende do que você está defendendo.Se for um invasor derrubando seu banco de dados (ou enganando seu aplicativo para que ele exiba o banco de dados), as senhas em texto simples serão inúteis.Existem muitos ataques que dependem de convencer o aplicativo a liberar seus dados privados - injeção de SQL, sequestro de sessão, etc.Muitas vezes é melhor não manter os dados, mas manter a versão com hash para que os bandidos não possam usá-los facilmente.

Como seu colega de trabalho sugere, isso pode ser derrotado trivialmente executando o mesmo algoritmo de hash em um dicionário e usando tabelas arco-íris para extrair as informações.A solução usual é usar um salt secreto mais informações adicionais do usuário para tornar os resultados do hash únicos - algo como:

String hashedPass=CryptUtils.MD5("alsdl;ksahglhkjfsdkjhkjhkfsdlsdf" + user.getCreateDate().toString() +  user.getPassword);

Contanto que seu salt seja secreto ou que seu invasor não saiba a data precisa de criação do registro do usuário, um ataque de dicionário falhará - mesmo no caso de ele conseguir extrair o campo de senha.

Nada é menos seguro do que armazenar senhas em texto simples.Se você estiver usando um algoritmo de hash decente (pelo menos SHA-256, mas mesmo SHA-1 é melhor que nada), então sim, colisões são possíveis, mas não importa porque dado um hash, é impossível* calcular o que strings hash para ele.Se você fizer o hash do nome de usuário COM a senha, essa possibilidade também desaparecerá.

* - tecnicamente não impossível, mas "computacionalmente inviável"

Se o nome de usuário for "graeme" e a senha for "stackoverflow", crie uma string "graeme-stackoverflow-1234" onde 1234 é um número aleatório, faça um hash e armazene "hashoutput1234" no banco de dados.Quando se trata de validar uma senha, pegue o nome de usuário, a senha fornecida e o número do final do valor armazenado (o hash tem um comprimento fixo para que você sempre possa fazer isso) e misture-os e compare-os com o hash parte do valor armazenado.

mais senhas poderiam corresponder ao hash e um ataque de dicionário/hash seria mais rápido.

Sim e não.Use um algoritmo de hash moderno, como uma variante SHA, e esse argumento será muito, muito fraco.Você realmente precisa se preocupar se esse ataque de força bruta durará apenas 352 anos em vez de 467 anos?(Piada anedótica aí.) O valor a ser obtido (não ter a senha armazenada em texto simples no sistema) supera em muito a preocupação do seu colega.

Espero que você me perdoe por incluir uma solução que escrevi sobre isso, usando JavaScript do lado do cliente para fazer o hash da senha antes de ela ser transmitida: http://blog.asgeirnilsen.com/2005/11/password-authentication-without.html

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top