É mais seguro usar hash em uma senha várias vezes?

39

Eu li algumas vezes que, ao armazenar senhas, é uma boa prática 'dobrar o hash' das cadeias de caracteres (por exemplo, com md5, em seguida, sha1, ambos com sais, obviamente).

Eu acho que a primeira pergunta é: "isso é realmente correto?" Se não, então, por favor, descarte o resto desta questão:)

A razão pela qual eu pergunto é que, em face disso, eu diria que isso faz sentido. No entanto, quando penso nisso, toda vez que um hash é reescrito (possivelmente com algo adicionado a ele), tudo o que posso ver é que há uma redução no limite superior na 'unicidade' final ... que está relacionada a a entrada inicial.

Deixe-me colocar de outra forma: temos um número x de strings que, quando hashed, são reduzidas a y strings possíveis. Ou seja, há colisões no primeiro conjunto. Agora vindo do segundo set para o terceiro, não é possível que a mesma coisa ocorra (ou seja, colisões no conjunto de todas as sequências 'y' possíveis que resultam no mesmo hash no terceiro conjunto)?

Na minha cabeça, tudo que vejo é um 'funil' para cada chamada de função hash, 'afunilando' um conjunto infinito de possibilidades em um conjunto finito e assim por diante, mas obviamente cada chamada está trabalhando no conjunto finito anterior, nos dando um conjunto não maior que a entrada.

Talvez um exemplo explique minhas divagações? Pegue 'hash_function_a' que dará 'a' e 'b' o hash '1', e dará 'c' e 'd' o hash '2'. Usando essa função para armazenar senhas, mesmo que a senha seja 'a', eu poderia usar a senha 'b'.

Pegue 'hash_function_b' que dará '1' e '2' o hash '3'. Se eu fosse usar it como um 'hash secundário' depois de 'hash_function_a' então mesmo que a senha fosse 'a' eu poderia usar 'b', 'c' ou 'd'.

Além de tudo isso, eu entendo que sais devem ser usados, mas eles realmente não mudam o fato de que toda vez que estamos mapeando 'x' entradas para saídas 'menores que x'. Eu não acho.

Alguém pode me explicar o que eu sinto falta aqui?

Obrigado!

EDIT: por que vale a pena, eu não faço isso sozinho, eu uso bcrypt. E eu não estou realmente preocupado se é ou não útil para 'usar ciclos' para um 'hacker'. Eu realmente estou apenas imaginando se o processo reduz ou não a 'segurança' de um ponto de vista de colisão de hash.

    
por Narcissus 20.10.2011 / 19:52
fonte

6 respostas

25

Isso é mais adequado em security.stackexchange, mas ...

O problema com

hash1(hash2(hash3(...hashn(pass+salt)+salt)+salt)...)+salt)

é que isso é tão strong quanto a função hash mais fraca da cadeia. Por exemplo, se hashn (o hash mais interno) der uma colisão, toda a cadeia hash dará uma colisão ( independentemente de quais outros hashes estão na cadeia ).

Uma cadeia mais strong seria

hash1(hash2(hash3(...hashn(pass + salt) + pass + salt) + pass + salt)...) + pass + salt)

Aqui, evitamos o problema de colisão inicial e basicamente geramos um sal que depende da senha do hash final.

E se um passo na cadeia colidir, não importa, porque na próxima etapa a senha é usada novamente e deve dar um resultado diferente para senhas diferentes.

    
por 20.10.2011 / 20:18
fonte
51

Usar diferentes algoritmos de hashing é uma má ideia - reduzirá a entropia em vez de aumentá-la.

No entanto, supondo que você tenha um algoritmo hash criptograficamente strong e um bom sal, aplicar a mesma função hash várias vezes torna o processo de hashing mais oneroso em termos computacionais. O benefício disso é que quando outros meios de quebrar o hash de senha falham (adivinhação, ataques de dicionário, tabelas de arco-íris, etc.) e o atacante é forçado a usar técnicas de força bruta, leva mais tempo para tentar cada senha, simplesmente porque eles precisam aplicar a mesma função hash com mais frequência. Portanto, se uma rodada de hashing exigir um mês de força bruta, aplicá-la doze vezes aumentaria o tempo estimado para um ano.

Algoritmos de hash recentes, como o bcrypt, baseiam-se nessa ideia; eles contêm um parâmetro para controlar a complexidade computacional do hash, para que você possa escalá-lo à medida que o hardware avança: quando o hardware se torna mais rápido por um fator de dois, você aumenta a complexidade para compensar. hashes permanece aproximadamente constante.

    
por 20.10.2011 / 22:08
fonte
3

Não tente escrever seu próprio esquema de hash de senha, a menos que esteja disposto a fazer um curso de engenharia de criptografia e / ou segurança.

Você deve usar uma implementação bem estabelecida de hashing de senha que, por sua vez, deve usar uma função de derivação de chave ( KDF ) como como PBKDF2, bcrypt, scrypt ou o mais recente Argon2.

Boas KDFs incluem um fator de trabalho, geralmente um número de iterações, para aumentar o custo de ataques offline. Pode-se dizer que esses KDFs criptografam a senha várias vezes, usando o mesmo algoritmo a cada vez. Não faz sentido usar o algoritmo de resumo de múltiplas mensagens, como apontado por outros.

    
por 15.10.2013 / 11:58
fonte
2

Em geral, você não precisa usar mais de um algoritmo de hash.

O que você precisa fazer é:

Use salt: salt não é usado apenas para tornar sua senha mais segura , é usada para evitar ataques de arco-íris. Dessa forma, alguém terá um trabalho mais difícil tentando pré-calcular o hash de senhas que você armazena em seu sistema.

Use múltiplas interações: ao invés de fazer apenas SHA (password + salt), faça SHA (SHA (SHA) (SHA (... SHA (password + salt)))))). Ou, para representar de outra maneira:

hash = sha(password + salt)
for i=1 , i=5000, i++ {
    hash = sha(hash + salt);
}

E, finalmente, escolha uma boa função hash. SHA, MD5, etc, não são bons porque são muito rápidos . Como você quer usar hash para proteção, é melhor usar hashes mais lentos. Dê uma olhada em Bcrypt , PBKDF2 ou Scrypt , por exemplo.

edit : depois das observações, vamos tentar ver alguns pontos (desculpe, longa explicação para chegar ao fim, porque isso pode ajudar outras pessoas a procurar por respostas semelhantes):

Se o seu sistema é seguro, como ninguém jamais terá acesso à senha armazenada, você não precisaria de hash. A senha seria secreta, ninguém conseguiria.

Mas ninguém pode garantir que o banco de dados com as senhas será roubado. Roube o banco de dados, pegue todas as senhas. Ok, seu sistema e sua empresa sofrerão todas as conseqüências disso. Então, poderíamos tentar evitar que essa senha vazasse.

AVISO de que não estamos preocupados com ataques online neste ponto. Para um ataque online, a melhor solução é desacelerar após senhas ruins, bloquear a conta após algumas tentativas, etc. E, para isso, não importa de que maneira você criptografa, armazena, armazena, etc., sua senha. Ataque on-line é uma questão de retardar as entradas de senha .

Então, voltemos ao problema don't let them take my plain passwords . A resposta é simples: não os armazene como texto simples. Ok, entendi.

Como evitar isso?

Criptografar a senha (?). Mas, como você sabe, se você criptografá-lo, você pode descriptografá-lo de volta, se você tiver a chave adequada. E você vai acabar com o problema de "onde esconder" a chave. Hum, não é bom, uma vez que você tem banco de dados, eles podem obter a sua chave. Ok, não vamos usar isso.

Então, outra abordagem: vamos transformar a senha em outra coisa que não pode ser revertida e armazená-la. E para verificar se a senha fornecida está correta, fazemos o mesmo processo novamente e verificamos se os dois valores transformados coincidem. Se eles corresponderem = a boa senha foi fornecida.

Ok, até aí tudo bem. Vamos usar algum hash MD5 na senha. Mas ... se alguém tiver nosso valor de senha armazenado em hash, ele pode ter muito poder computacional para calcular o hash MD5 de todas as senhas possíveis (força bruta), para que ele possa encontrar a senha original. Ou, pior ainda, ele pode armazenar todo o MD5 de todas as combinações de caracteres e encontrar facilmente a senha. Então, faça muitas iterações, a coisa HASH (HASH (HASH ())), para tornar isso mais difícil, porque vai demorar mais tempo.

Mas mesmo isso pode ser contornado, a mesa do arco-íris foi criada exatamente para acelerar esse tipo de proteção.

Então, vamos usar um pouco de sal sobre ele. Desta forma, a cada interação, o sal é usado novamente. Uma tentativa de atacar suas senhas terá que gerar a tabela do arco-íris, considerando que o sal é adicionado a cada vez. E quando ele gera aquela tabela do arco-íris, já que ela foi gerada com um sal, ele terá que calcular novamente com o outro sal, então ele terá que gastar algum tempo para cada senha (= cada sal). Sal não adiciona "mais complexidade" à senha, apenas faz o atacante perder tempo gerando a tabela do arco-íris, se você usar um sal para cada senha, a tabela de um sal é inútil para outra senha.

E usar mais de um hash terá ajudado aqui? Não. A pessoa que gera um ataque arco-íris específico poderá gerá-lo usando um ou mais hashes, de qualquer forma.

E o uso de mais de um hash pode levar você a um problema: é tão seguro quanto o hash mais fraco que você usa. Se alguém encontrar colisões em um algoritmo de hash, esse hash será explorado, em qualquer ponto do processo de iteração, para quebrar a senha. Então, você não ganha nada usando mais hashes de algoritmos, é melhor escolher apenas um bom algoritmo. e usá-lo. E se você já ouviu que foi quebrado, pense em como você vai mudar isso em sua aplicação.

E por que usar o bcrypt ou algo assim (você diz que o usa): porque o invasor terá que gastar mais tempo gerando as tabelas. É por isso que usar MD5 + wait (3 segundos) não ajuda: o ataque estará off-line, de qualquer forma, para que o invasor possa gerar as tabelas sem o (atraso de 3 segundos).

    
por 20.10.2011 / 20:10
fonte
-1

Meu entendimento é que usar vários algoritmos hash é derrotar as tabelas do arco-íris . Usar um bom sal também funciona, mas acho que é um segundo nível de proteção.

    
por 20.10.2011 / 20:36
fonte
-1

Isso não é mais seguro. No entanto, você tem um protocolo de identificação baseado em hash várias vezes com a mesma função.

Isso é assim. O valor armazenado é hash ^ n (pass) no computador A. A pergunta B para autenticar e dá B o inteiro n. B faz o cálculo hash ^ (n-1) (pass) e envia de volta para A.

Uma verificação que hash (hash ^ (n-1) (passe)) == hash ^ n (pass). Se é verdade, então a autenticação é feita. Mas então, A store hash ^ (n-1) (pass) e next authentication, dará B n-1 ao invés de n.

Isso garante que a senha nunca seja trocada de forma clara, que A nunca sabe o que é a senha e que a autenticação é protegida pelo replay. No entanto, isso tem a desvantagem de exigir senha com um tempo de vida finito. Quando n atingir o valor 2, uma nova senha deve ser escolhida após a autenticação.

Outro uso de vários hash é a ferramenta HMAC, para garantir a autenticidade e a integridade de uma solicitação. Para mais informações sobre o HMAC, consulte o link .

A maioria dos usos de múltiplos hash no mundo real é um exagero. No seu caso, parece ser. Observe que, se você usar várias funções de hash, elas não terão todas a mesma entropia, portanto, isso reduzirá a força do hash. Por exemplo, md5 tem menos entropia que sha1, então usar sha1 em um md5 não irá melhorar a força do hash. A força geralmente será igual à força da função hash mais fraca.

    
por 20.10.2011 / 21:29
fonte

Tags