Que tipo de dados usar para o campo de senha com hash e qual o comprimento?

269

Não tenho certeza de como o hash de senha funciona (será implementado posteriormente), mas preciso criar o esquema do banco de dados agora.

Estou pensando em limitar as senhas para 4-20 caracteres, mas como eu entendo depois de criptografar a seqüência de hash terá comprimento diferente.

Então, como armazenar essas senhas no banco de dados?

z-boss
fonte
Veja também a estrutura de hash de senha PHP do Openwall (PHPass). É portátil e reforçado contra uma série de ataques comuns a senhas de usuários. O cara que escreveu a estrutura (SolarDesigner) é o mesmo que escreveu John The Ripper e atua como juiz na Competição de Hashing de Senhas . Então ele sabe uma coisa ou duas sobre ataques a senhas.
JWW
2
Por favor, não coloque um limite superior em suas senhas. Você os está hashando, não há motivo de armazenamento para um limite superior. Se você está preocupado com ataques de negação de serviço usando o hash da senha, 1000 ou 1024 é um limite superior razoável.
Iiridayn
por que limitar o tamanho da senha? Pelo menos permitir que um usuário criar uma senha de 100 caracteres :)
Andrew
4 caracteres é um limite inferior bastante perigoso para senhas, pois essas são triviais para quebrar. No mínimo, use 8, mas 14 ou 16 é muito melhor.
QuikChange
Esta é uma pergunta muito antiga, com uma resposta desatualizada. Veja a resposta de Gilles para atualizar.
Kelalaka 18/04/19

Respostas:

448

Atualização: o simples uso de uma função hash não é forte o suficiente para armazenar senhas. Você deve ler a resposta de Gilles neste tópico para obter uma explicação mais detalhada.

Para senhas, use um algoritmo de hash de reforço de chave como Bcrypt ou Argon2i. Por exemplo, no PHP, use a função password_hash () , que usa Bcrypt por padrão.

$hash = password_hash("rasmuslerdorf", PASSWORD_DEFAULT);

O resultado é uma cadeia de 60 caracteres semelhante à seguinte (mas os dígitos variam, porque gera um sal exclusivo).

$2y$10$.vGA1O9wmRjrwAVXD98HNOgsNpDczlqm3Jq7KnEd1rVAGv3Fykk1a

Use o tipo de dados SQL CHAR(60)para armazenar essa codificação de um hash Bcrypt. Observe que essa função não codifica como uma sequência de dígitos hexadecimais, portanto, não podemos facilmente desencaixá-la para armazenar em binário.

Outras funções de hash ainda têm usos, mas não para armazenar senhas, por isso vou manter a resposta original abaixo, escrita em 2008.


Depende do algoritmo de hash que você usa. O hash sempre produz um resultado do mesmo comprimento, independentemente da entrada. É típico representar o resultado do hash binário no texto, como uma série de dígitos hexadecimais. Ou você pode usar oUNHEX() função para reduzir pela metade uma sequência de dígitos hexadecimais.

  • MD5 gera um valor de hash de 128 bits. Você pode usar CHAR (32) ou BINARY (16)
  • SHA-1 gera um valor de hash de 160 bits. Você pode usar CHAR (40) ou BINARY (20)
  • O SHA-224 gera um valor de hash de 224 bits. Você pode usar CHAR (56) ou BINARY (28)
  • O SHA-256 gera um valor de hash de 256 bits. Você pode usar CHAR (64) ou BINARY (32)
  • O SHA-384 gera um valor de hash de 384 bits. Você pode usar CHAR (96) ou BINARY (48)
  • O SHA-512 gera um valor de hash de 512 bits. Você pode usar CHAR (128) ou BINARY (64)
  • BCrypt gera um valor de hash de 448 bits dependente da implementação. Pode ser necessário CHAR (56), CHAR (60), CHAR (76), BINARY (56) ou BINARY (60)

A partir de 2015, o NIST recomenda o uso do SHA-256 ou superior para quaisquer aplicativos de funções de hash que exijam interoperabilidade. Mas o NIST não recomenda o uso dessas funções simples de hash para armazenar senhas com segurança.

Algoritmos de hash menores têm seus usos (como internos a um aplicativo, não para intercâmbio), mas são conhecidos por serem quebráveis .

Bill Karwin
fonte
47
@ Hippo: Por favor, não use o nome de usuário como o sal. Gere um sal aleatório por usuário.
Bill Karwin
11
Sim, não há razão para não armazená-lo na mesma linha. Mesmo que um invasor obtenha acesso ao seu banco de dados, ele terá que construir sua tabela arco-íris com base nesse sal. E isso é tão trabalhoso quanto simplesmente adivinhar a senha.
Bill Karwin
5
@SgtPooki: Você precisa de outra coluna para armazenar o sal em texto simples. Em seguida, você pode fazer o hash da senha do usuário com o mesmo sal quando eles a digitarem e comparar o resultado com o resumo de hash armazenado na tabela.
Bill Karwin
12
Se você estiver armazenando o salt na mesma tabela (ou em qualquer outro local com as mesmas permissões de acesso), não há razão para não usar o nome de usuário como o salt, pois ele será exclusivo por usuário. No entanto, qualquer sal conhecido torna o hash criptograficamente mais fraco do que se não houvesse sal conhecido. Um sal só agrega valor se também for desconhecido.
Fijiaaron 18/05
9
Não entendo o acordo com sal conhecido x desconhecido. Se você estiver implementando um site - o salt precisa ser conhecido na página de login / script / sevice que está testando a senha. Então - vocês "desconhecidos" advogados do sal - estão assumindo que o código para o processo de login é desconhecido do invasor? Caso contrário - o atacante não saberá sempre o sal, seja aleatório, único, armazenado junto com a senha com hash ou separado?
mattstuehler
13

Você pode realmente usar CHAR(comprimento do hash) para definir seu tipo de dados para o MySQL, porque cada algoritmo de hash sempre será avaliado com o mesmo número de caracteres. Por exemplo, SHA1sempre retorna um número hexadecimal de 40 caracteres.

Noah Goodrich
fonte
1
SHA-1 não é adequado para hash de senhas.
Gilles 'SO- stop be evil'
10

Sempre use um algoritmo de hash de senha: Argon2 , scrypt , bcrypt ou PBKDF2 .

Argon2 venceu a competição de hash de senha de 2015. Scrypt , bcrypt e PBKDF2 são algoritmos mais antigos que são considerados menos preferidos agora, mas ainda são fundamentalmente sólidos, portanto, se sua plataforma ainda não suporta Argon2, não há problema em usar outro algoritmo por enquanto.

Nunca armazene uma senha diretamente em um banco de dados. Também não criptografe: caso contrário, se o site for violado, o invasor receberá a chave de descriptografia e poderá obter todas as senhas. As senhas devem ser hash .

Um hash de senha tem propriedades diferentes de um hash da tabela de hash ou de um hash criptográfico. Nunca use um hash criptográfico comum, como MD5, SHA-256 ou SHA-512 em uma senha. Um algoritmo de hash de senha usa um salt , que é único (não usado para nenhum outro usuário ou no banco de dados de ninguém). O salt é necessário para que os invasores não possam apenas pré-calcular os hashes de senhas comuns: com um salt, eles precisam reiniciar o cálculo para todas as contas. Um algoritmo de hash de senha é intrinsecamente lento - o mais lento possível. A lentidão prejudica muito mais o invasor do que você, porque o invasor precisa tentar muitas senhas diferentes. Para obter mais informações, consulte Como proteger senhas de hash com segurança .

Um hash de senha codifica quatro informações:

  • Um indicador de qual algoritmo é usado. Isso é necessário para agilidade : as recomendações criptográficas mudam com o tempo. Você precisa poder fazer a transição para um novo algoritmo.
  • Um indicador de dificuldade ou dureza. Quanto maior esse valor, mais computação é necessária para calcular o hash. Esse deve ser um valor de configuração constante ou global na função de alteração de senha, mas deve aumentar com o tempo à medida que os computadores ficam mais rápidos, portanto, é necessário lembrar o valor de cada conta. Alguns algoritmos têm um único valor numérico, outros possuem mais parâmetros (por exemplo, para ajustar o uso da CPU e o uso da RAM separadamente).
  • O sal. Como o sal deve ser globalmente exclusivo, ele deve ser armazenado para cada conta. O sal deve ser gerado aleatoriamente em cada alteração de senha.
  • O hash próprio, ou seja, a saída do cálculo matemático no algoritmo de hash.

Muitas bibliotecas incluem funções de par que empacotam convenientemente essas informações como uma única sequência: uma que aceita o indicador de algoritmo, o indicador de dureza e a senha, gera um sal aleatório e retorna a sequência completa de hash; e uma que usa uma senha e a cadeia de hash completa como entrada e retorna um booleano indicando se a senha estava correta. Não existe um padrão universal, mas uma codificação comum é

$ algoritmo $ parâmetros $ salt $ saída

onde algorithmé um número ou uma sequência alfanumérica curta que codifica a escolha do algoritmo, parametersé uma sequência imprimível salte outputé codificada em Base64 sem terminar= .

16 bytes são suficientes para o sal e a saída. (Veja, por exemplo, recomendações para Argon2 .) Codificado em Base64, com 21 caracteres cada. As outras duas partes dependem do algoritmo e dos parâmetros, mas 20 a 40 caracteres são típicos. No total, são cerca de 82 caracteres ASCII ( CHAR(82)e não há necessidade de Unicode), aos quais você deve adicionar uma margem de segurança se achar que será difícil ampliar o campo posteriormente.

Se você codificar o hash em um formato binário, poderá reduzi-lo a 1 byte para o algoritmo, 1 a 4 bytes para a dureza (se você codificar alguns dos parâmetros) e 16 bytes cada para o salt e a saída , para um total de 37 bytes. Diga 40 bytes (BINARY(40) ) para ter pelo menos alguns bytes sobressalentes. Observe que esses são bytes de 8 bits, caracteres não imprimíveis, em particular o campo pode incluir bytes nulos.

Observe que o comprimento do hash não tem nenhuma relação com o comprimento da senha.

Gilles 'SO- parar de ser mau'
fonte
9

Você pode encontrar este artigo da Wikipedia sobre salga que vale a pena . A idéia é adicionar um conjunto de dados para randomizar seu valor de hash; isso protegerá suas senhas contra ataques de dicionário se alguém obtiver acesso não autorizado aos hashes de senha.

Dana the Sane
fonte
2
Isso vale muito a pena (+1), mas não responde à pergunta! (-1)
Bill Karwin 29/08/08
3
Sim, mas definitivamente relevante nesse contexto (+1)
Treb 29/10/08
7

Como uma string de comprimento fixo (VARCHAR (n) ou como o MySQL chama). Um hash sempre tem um comprimento fixo de, por exemplo, 12 caracteres (dependendo do algoritmo de hash usado). Portanto, uma senha de 20 caracteres seria reduzida para um hash de 12 caracteres e uma senha de 4 caracteres também produziria um hash de 12 caracteres.

Treb
fonte
3
'ou como o MySQL chama' - MYSQL chama CHAR. Este tipo é para valor de comprimento fixo. Então eu acho que CHAR é melhor do que VARCHAR.
t298712383
4

Você deve usar TEXT(armazenar um número ilimitado de caracteres) para obter compatibilidade futura. Os algoritmos de hash (precisam) se tornam mais fortes com o tempo e, portanto, esse campo do banco de dados precisará suportar mais caracteres ao longo do tempo. Além disso, dependendo da sua estratégia de migração, pode ser necessário armazenar hashes novos e antigos no mesmo campo, portanto, não é recomendável fixar o comprimento em um tipo de hash.

bart
fonte
3

Realmente depende do algoritmo de hash que você está usando. O tamanho da senha tem pouco a ver com o tamanho do hash, se bem me lembro. Consulte as especificações do algoritmo de hash que você está usando, execute alguns testes e trunque logo acima.

willasaywhat
fonte
3

Hashes são uma sequência de bits (128 bits, 160 bits, 256 bits etc., dependendo do algoritmo). Sua coluna deve ser do tipo binário, não do texto / caractere, se o MySQL permitir (o tipo de dados do SQL Server é binary(n)ou varbinary(n)). Você também deve salgar os hashes. Os sais podem ser de texto ou binários, e você precisará de uma coluna correspondente.

yfeldblum
fonte
A justiça está completamente correta aqui - o MySQL os armazenará como valores numéricos e tornará a pesquisa nesta coluna muito mais eficiente do que fazer uma correspondência de string, no entanto, os sais não devem ser armazenados no banco de dados ao lado dos dados salgados - isso elimina a segurança que os sais fornecem .
precisa
6
Os sais não são secretos. O único segredo é a senha. Apenas certifique-se de que cada nova senha receba um novo sal. Cada vez que o usuário altera sua senha, o sistema deve gerar um novo sal para essa senha. Os sais devem ser longos e aleatórios, como 16 bytes gerados a partir de um PRNG criptograficamente seguro.
yfeldblum
1
@TonyMaro Não tenho certeza se uma string de senha corresponde ao nível SQL é uma boa estratégia. Em outras palavras, você não deve procurar uma senha no banco de dados; em vez disso, recupere o usuário com base em seu nome de usuário e compare as senhas no código, em vez de no SQL.
Bart
1

Eu sempre testei para encontrar o comprimento máximo da string criptografada e defini-lo como o comprimento do caractere de um tipo VARCHAR. Dependendo de quantos registros você terá, isso pode realmente ajudar o tamanho do banco de dados.

Stephen Walcher
fonte
0

para md5, o vARCHAR (32) é apropriado. Para quem usa AES, é melhor usar varbinary.

Hare Srinivasa
fonte
1
Nem MD5, nem AES são adequados para hash uma senha.
Gilles 'SO- stop be evil'