Hash de senha, salt e armazenamento de valores de hash

Suponha que você tenha a liberdade de decidir como as senhas em hash devem ser armazenadas em um DBMS. Existem deficiências óbvias em um esquema como este?

Para criar o valor de hash armazenado no DBMS, leve:

  • Um valor que é exclusivo para a instância do servidor DBMS como parte do sal,
  • E o nome de usuário como uma segunda parte do sal,
  • E crie a concatenação do sal com a senha real,
  • E hash toda a string usando o algoritmo SHA-256,
  • E armazene o resultado no DBMS.

Isso significaria que qualquer pessoa que quisesse criar uma colisão deveria fazer o trabalho separadamente para cada nome de usuário e cada instância do servidor DBMS separadamente. Eu planejo manter o mecanismo de hash real um pouco flexível para permitir o uso do novo algoritmo de hash padrão do NIST ( SHA-3 ) que ainda está sendo trabalhado.

O ‘valor que é exclusivo para a instância do servidor DBMS’ não precisa ser secreto – embora não seja divulgado casualmente. A intenção é garantir que, se alguém usar a mesma senha em diferentes instâncias do servidor DBMS, os hashes registrados sejam diferentes. Da mesma forma, o nome do usuário não seria secreto – apenas a senha apropriada.

Haveria alguma vantagem em ter a senha em primeiro lugar e o nome do usuário e o ‘valor único’ em segundo, ou qualquer outra permutação das três fonts de dados? Ou que tal intercalar as cordas?

Preciso adicionar (e gravar) um valor de sal random (por senha), bem como as informações acima? (Vantagem: o usuário pode reutilizar uma senha e ainda assim, provavelmente, obter um hash diferente registrado no database. Desvantagem: o sal tem que ser registrado. Eu suspeito que a vantagem supera consideravelmente a desvantagem.)

Há muitas perguntas SO relacionadas – é improvável que essa lista seja abrangente:

  • Criptografando / Hash de senhas de texto simples no database
  • Secure hash and salt para senhas do PHP
  • A necessidade de esconder o sal para um hash
  • Md5 do lado do cliente hash com sal do tempo
  • Criptografia de senha simples
  • Geração de sal e software de código aberto
  • Hashes de senha: campos binários de comprimento fixo ou campo de cadeia única?

Eu acho que as respostas para essas perguntas suportam meu algoritmo (embora se você simplesmente usar um salt random, então os componentes ‘unique value per server’ e username são menos importantes).

O sal só precisa ser random e único. Pode ser conhecido como não ajuda um atacante. Muitos sistemas armazenam o sal de texto simples no database na coluna ao lado da senha com hash.

O sal ajuda a garantir que se duas pessoas (Usuário A e Usuário B) compartilharem a mesma senha, isso não é óbvio. Sem o sal random e exclusivo para cada senha, os valores de hash seriam os mesmos e, obviamente, se a senha do Usuário A fosse quebrada, o Usuário B teria a mesma senha.

Ele também ajuda a proteger contra ataques em que um dictionary de hashes pode ser comparado a senhas conhecidas. por exemplo, mesas de arco-íris.

Também usar um algoritmo com um “fator de trabalho” embutido também significa que, à medida que o poder computacional aumenta, o trabalho que um algoritmo tem que percorrer para criar o hash também pode ser aumentado. Por exemplo, bcrypt . Isso significa que a economia dos ataques de força bruta se torna insustentável. Presumivelmente, torna-se muito mais difícil criar tabelas de hashes conhecidos, porque demoram mais tempo para criar; as variações no “fator trabalho” significarão que mais tabelas teriam que ser construídas.

Eu acho que você está complicando demais o problema.

Comece com o problema:

  1. Você está tentando proteger senhas fracas?
  2. Você está tentando mitigar ataques de arco-íris?

O mecanismo que você propõe protege contra um simples ataque de arco-íris, mesmo que o usuário A e o usuário B tenham a mesma senha, a senha com hash será diferente. Parece um método bastante elaborado salgar uma senha que é excessivamente complicada.

  • O que acontece quando você migra o database para outro servidor?
    • Você pode alterar o valor único, por DB, se assim for, em seguida, uma tabela global do arco-íris pode ser gerada, se não, então você não pode restaurar seu database.

Em vez disso, basta adicionar a coluna extra e armazenar um sal random adequado. Isso protegeria contra qualquer tipo de ataque de arco-íris. Em várias implantações.

No entanto, não irá protegê-lo contra um ataque de força bruta. Então, se você está tentando proteger os usuários que têm senhas ruins, você precisará procurar em outro lugar. Por exemplo, se seus usuários tiverem 4 senhas de letras, provavelmente elas poderão ser quebradas em segundos, mesmo com um algoritmo hash e o mais recente.

Eu acho que você precisa se perguntar “O que você está esperando para ganhar fazendo isso mais complicado do que apenas gerar um valor de sal random e armazená-lo?” Quanto mais complicado você criar seu algoritmo, maior a probabilidade de você introduzir uma fraqueza inadvertidamente. Isso provavelmente soará sarcástico, não importa como eu o diga, mas é útil – o que há de tão especial no seu aplicativo que ele precisa de um novo e sofisticado algoritmo hash de senhas?

Por que não adicionar um sal random à senha e hash essa combinação. Em seguida, concatene o hash e o sal em um único byte [] e armazene-o no db?

A vantagem de um sal random é que o usuário está livre para mudar seu nome de usuário. O sal não precisa ser secreto, pois é usado para evitar ataques de dictionary.