Armazenando valores de hash SHA1 no MySQL

160

Eu tenho uma pergunta simples que ocorreu quando eu queria armazenar o resultado de um hash SHA1 em um banco de dados MySQL:

Quanto tempo deve estar o campo VARCHAR no qual armazeno o resultado do hash?

Niklasfi
fonte
9
Se você apenas pesquisou no sha1, clique em que estou com sorte e você deve estar na wikipedia, onde você pode encontrar sempre 160 bits.
Tim Matthews

Respostas:

315

Eu usaria VARCHARpara dados de comprimento variável, mas não com dados de comprimento fixo. Como um valor SHA-1 sempre tem 160 bits, VARCHARseria apenas um byte adicional para o comprimento do campo de comprimento fixo .

E eu também não armazenaria o valor que SHA1está retornando. Porque ele usa apenas 4 bits por caractere e, portanto, precisaria de 160/4 = 40 caracteres. Mas se você usar 8 bits por caractere, precisará apenas de um campo de 160/8 = 20 caracteres.

Então, eu recomendo que você use BINARY(20)e a UNHEXfunção para converter o SHA1valor em binário.

Comparei os requisitos de armazenamento para BINARY(20)e CHAR(40).

CREATE TABLE `binary` (
    `id` int unsigned auto_increment primary key,
    `password` binary(20) not null
);
CREATE TABLE `char` (
    `id` int unsigned auto_increment primary key,
    `password` char(40) not null
);

Com milhões de registros binary(20)leva 44,56M, enquanto char(40)leva 64,57M. InnoDBmotor.

quiabo
fonte
2
No PostgreSQL, isso se traduz em usar um campo bytea, certo?
mvexel
A solução é ótima, mas há outro ponto para usar char (40) com sha1 hexadecimal - isso é muito mais usado e haverá menos problemas de conversão em um código de aplicativo.
Arthur Kushman 9/09/13
2
Nota para usuários do phpmyadmin. Ao armazenar o hash como binário, o phpmyadmin o exibirá como uma sequência hexadecimal, mas o pma não poderá usá-lo na "guia de pesquisa" fornecida. Funcionará apenas se você adicionar UNHEX()manualmente ao sql.
Timo Huovinen
2
@Gumbo Você pode armazenar um número variável de bytes em um bytea. Você está se referindo aos requisitos de armazenamento do tipo bytea. Que é "1 ou 4 bytes mais a cadeia binária real". O que o "1 ou 4" se refere pode ser o comprimento dos dados armazenados, pois você não pode usar um byte zero para finalizar a string, como faz com varchar. Isso implica, mas não está declarado no manual, que você pode armazenar até 2 ^ (8 * 4) ou mais de 4 gigabytes em um bytea. postgresql.org/docs/9.0/static/datatype-binary.html O armazenamento do hash em um banco de dados postgres provavelmente seria o menor como uma coluna de bits ou bytea.
Viktor
2
dev.mysql.com/doc/refman/5.5/en/... fornece informação sobre o desempenho e o armazenamento quando armazenar resultados de funções cripta
Clocker
45

Um hash SHA1 tem 40 caracteres!

schmilblick
fonte
11

Referência retirada deste blog:

Abaixo está uma lista do algoritmo de hash junto com seu tamanho de bit requerido:

  • MD5 = valor de hash de 128 bits.
  • SHA1 = valor de hash de 160 bits.
  • SHA224 = valor de hash de 224 bits.
  • SHA256 = valor de hash de 256 bits.
  • SHA384 = valor de hash de 384 bits.
  • SHA512 = valor de hash de 512 bits.

Criou uma tabela de amostra com CHAR (n) requerido:

CREATE TABLE tbl_PasswordDataType
(
    ID INTEGER
    ,MD5_128_bit CHAR(32)
    ,SHA_160_bit CHAR(40)
    ,SHA_224_bit CHAR(56)
    ,SHA_256_bit CHAR(64)
    ,SHA_384_bit CHAR(96)
    ,SHA_512_bit CHAR(128)
); 
INSERT INTO tbl_PasswordDataType
VALUES 
(
    1
    ,MD5('SamplePass_WithAddedSalt')
    ,SHA1('SamplePass_WithAddedSalt')
    ,SHA2('SamplePass_WithAddedSalt',224)
    ,SHA2('SamplePass_WithAddedSalt',256)
    ,SHA2('SamplePass_WithAddedSalt',384)
    ,SHA2('SamplePass_WithAddedSalt',512)
);
Anvesh
fonte
10
Por favor , por favor , não armazene senhas como esta.
Berry M.
Hey berry, você pode explicar o seu POR QUE? em detalhes
Anvesh
4
Armazenar hashes simples de senhas facilita a extração de senhas se o banco de dados estiver comprometido do que se você usar um hash de senha salgado (que se espera esticado). Leitura sugerida: paragonie.com/blog/2016/02/how-safely-store-password-in-2016
matt
2
@BerryM. lendo isso um ano depois, e não pensei por um segundo que alguém estivesse falando sobre senhas ou que se as pessoas ainda usassem hash simples para armazenar dados de autenticação. Mas eles fazem: D
Rohit Hazra
6

O tamanho da saída de sha1 é de 160 bits. Que é 160/8 == 20 caracteres (se você usar caracteres de 8 bits) ou 160/16 = 10 (se você usar caracteres de 16 bits).

inazaruk
fonte
Assumindo caracteres binários de 8 bits. 40 caracteres se armazenados como hexadecimal.
Tyzoid 26/08/13
3

Portanto, o comprimento está entre 10 caracteres de 16 bits e 40 dígitos hexadecimais.

De qualquer forma, decida o formato que você deseja armazenar e torne o campo um tamanho fixo com base nesse formato. Dessa forma, você não terá espaço desperdiçado.

Douglas Leeder
fonte
2

Você ainda pode usar o VARCHAR nos casos em que nem sempre armazena um hash para o usuário (ou seja, autenticar contas / esquecer o URL de login). Depois que um usuário tiver autenticado / alterado suas informações de login, ele não poderá mais usar o hash e não deverá ter motivos para isso. Você pode criar uma tabela separada para armazenar hash temporário -> associações de usuários que podem ser excluídas, mas acho que a maioria das pessoas não se preocupa em fazer isso.

Keith Harty
fonte
2

Se você precisar de um índice na coluna sha1, sugiro CHAR (40) por razões de desempenho. No meu caso, a coluna sha1 é um token de confirmação de email, portanto, na página de entrada, a consulta entra apenas com o token. Nesse caso, CHAR (40) com INDEX, na minha opinião, é a melhor escolha :)

Se você deseja adotar esse método, lembre-se de deixar $ raw_output = false.

Francesco Casula
fonte
1
Por que você não indexaria BINARY (20)? Não seria tão rápido e metade do tamanho?
nickdnk 5/02
Bem, isso ~ 5 anos atrás, mas eu acho que estava me referindo ao fato de que você ainda precisa liberar o hex, o que adiciona um pouco de carga (+ torna o aplicativo mais difícil de manter e menos portátil?). Depende também do seu hardware, se você tiver menos armazenamento e for lento, provavelmente também será melhor manter o binário (20), caso contrário, eu diria char (40). Difícil dizer sem executar alguns testes com o idioma e o hardware que você usaria e ver o que melhor combina com você.
Francesco Casula
1
Suponho que se você estiver fazendo algo diferente de selecionar de onde unhex (hash) = hash para buscar uma única linha, talvez esteja certo. Mas manter o índice em buffer consumirá o dobro de memória dessa maneira.
nickdnk 6/02