Almacenar valores hash SHA1 en MySQL

160

Tengo una pregunta simple que ocurrió cuando quería almacenar el resultado de un hash SHA1 en una base de datos MySQL:

¿Cuánto tiempo debe estar el campo VARCHAR en el que almaceno el resultado del hash?

niklasfi
fuente
9
Si acaba de buscar en Google sha1, me siento afortunado y debería estar en Wikipedia donde puede encontrar que siempre tiene 160 bits.
Tim Matthews el

Respuestas:

315

Lo usaría VARCHARpara datos de longitud variable, pero no con datos de longitud fija. Debido a que un valor SHA-1 siempre tiene una longitud de 160 bits, VARCHARsimplemente desperdiciaría un byte adicional para la longitud del campo de longitud fija .

Y tampoco almacenaría el valor que SHA1está devolviendo. Porque usa solo 4 bits por carácter y, por lo tanto, necesitaría 160/4 = 40 caracteres. Pero si usa 8 bits por carácter, solo necesitaría un campo largo de 160/8 = 20 caracteres.

Por lo tanto, le recomiendo que use BINARY(20)y la UNHEXfunción para convertir el SHA1valor a binario.

Comparé los requisitos de almacenamiento para BINARY(20)y 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
);

Con millones de registros binary(20)toma 44.56M, mientras que char(40)toma 64.57M. InnoDBmotor.

Gumbo
fuente
2
En PostgreSQL, esto se traduciría en el uso de un campo bytea, ¿verdad?
mvexel
La solución es excelente, pero hay otro punto para usar char (40) con hexadecimal sha1: es mucho más utilizado y habrá menos problemas de conversión en un código de aplicación.
Arthur Kushman
2
Nota para usuarios de phpmyadmin. Al almacenar el hash como binario, phpmyadmin lo mostrará como una cadena hexadecimal, pero pma no podrá usarlo en la "pestaña de búsqueda" proporcionada. Solo funcionará si agrega UNHEX()manualmente al sql.
Timo Huovinen
2
@Gumbo Puede almacenar un número variable de bytes en un bytea. Se refiere a los requisitos de almacenamiento del tipo bytea. Que es "1 o 4 bytes más la cadena binaria real". A lo que se refiere el "1 o 4" podría ser la longitud de los datos almacenados, ya que no puede usar un byte cero para finalizar la cadena como lo hace con varchar. Eso implica, pero no se indica en el manual, que puede almacenar hasta 2 ^ (8 * 4) o 4+ gigabytes en un bytea. postgresql.org/docs/9.0/static/datatype-binary.html Almacenar el hash en una base de datos de postgres probablemente sería más pequeño como un bit o una columna bytea.
Viktor
2
dev.mysql.com/doc/refman/5.5/en/… proporciona información sobre el rendimiento y el almacenamiento al almacenar los resultados de las funciones de la cripta
Clocker
45

¡Un hash SHA1 tiene 40 caracteres de largo!

Schmilblick
fuente
11

Referencia tomada de este blog:

A continuación se muestra una lista de algoritmos de hash junto con su tamaño de bit requerido:

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

Se creó una tabla de muestra con require CHAR (n):

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
fuente
10
Por favor , por favor , en realidad no almacene contraseñas como esta.
Berry M.
Hola baya, ¿puedes explicar tu POR QUÉ? en detalles
Anvesh
44
El almacenamiento de hashes simples de contraseñas hace que sea mucho más fácil "extraer" las contraseñas si su base de datos se ve comprometida que si usa un hash de contraseña salado (con suerte estirado). Lectura sugerida: paragonie.com/blog/2016/02/how-safely-store-password-in-2016
mate
2
@BerryM. Leí esto un año después, y no pensé por un segundo que alguien estaba hablando de contraseñas o que si la gente todavía usa un hash simple para almacenar datos de autenticación. Pero lo hacen: D
Rohit Hazra
6

El tamaño de salida de sha1 es de 160 bits. Que es 160/8 == 20 caracteres (si usa caracteres de 8 bits) o 160/16 = 10 (si usa caracteres de 16 bits).

inazaruk
fuente
Asumiendo caracteres binarios de 8 bits. 40 caracteres si se almacenan como hex.
Tyzoid
3

Por lo tanto, la longitud es de entre 10 caracteres de 16 bits y 40 dígitos hexadecimales.

En cualquier caso, decida el formato que va a almacenar y haga que el campo tenga un tamaño fijo basado en ese formato. De esa manera no tendrá ningún espacio desperdiciado.

Douglas Leeder
fuente
2

Es posible que aún desee utilizar VARCHAR en casos en los que no siempre almacena un hash para el usuario (es decir, autenticación de cuentas / URL de inicio de sesión olvidada). Una vez que un usuario ha autenticado / cambiado su información de inicio de sesión, no debería poder usar el hash y no debería tener ninguna razón para hacerlo. Podría crear una tabla separada para almacenar hash temporal -> asociaciones de usuarios que podrían eliminarse, pero no creo que la mayoría de las personas se molesten en hacer esto.

Keith Harty
fuente
2

Si necesita un índice en la columna sha1, sugiero CHAR (40) por razones de rendimiento. En mi caso, la columna sha1 es un token de confirmación de correo electrónico, por lo que en la página de destino la consulta solo ingresa con el token. En este caso CHAR (40) con INDEX, en mi opinión, es la mejor opción :)

Si desea adoptar este método, recuerde dejar $ raw_output = false.

Francesco Casula
fuente
1
¿Por qué no indexarías BINARY (20)? ¿No sería tan rápido y la mitad de grande?
nickdnk
Bueno, esto hace ~ 5 años, pero creo que me estaba refiriendo al hecho de que todavía necesita eliminar errores que agrega algo de carga (¿+ hace que la aplicación sea más difícil de mantener y menos portátil?). Depende un poco de tu hardware también, si tienes menos almacenamiento y es lento, probablemente también sea mejor seguir el binario (20), de lo contrario, diría char (40). Es difícil de decir sin ejecutar algunas pruebas con el idioma y el hardware que usaría y ver qué le conviene más.
Francesco Casula
1
Supongo que si está haciendo algo más que seleccionar desde donde unhex (hash) = hash para buscar una sola fila, entonces tal vez tenga razón. Pero mantener el índice almacenado en memoria intermedia tomará el doble de memoria de esta manera.
nickdnk