¿Qué tipo de datos usar para el campo de contraseña hash y qué longitud?

269

No estoy seguro de cómo funciona el hashing de contraseñas (lo implementaremos más adelante), pero necesito crear un esquema de base de datos ahora.

Estoy pensando en limitar las contraseñas a 4-20 caracteres, pero según tengo entendido, después de cifrar la cadena hash será de diferente longitud.

Entonces, ¿cómo almacenar estas contraseñas en la base de datos?

z-boss
fuente
Consulte también el marco de hashing de contraseñas PHP de Openwall (PHPass). Es portátil y reforzado contra una serie de ataques comunes a las contraseñas de los usuarios. El tipo que escribió el marco (SolarDesigner) es el mismo tipo que escribió John The Ripper y se sienta como juez en la Competencia de hash de contraseñas . Entonces sabe una o dos cosas sobre los ataques a las contraseñas.
jww
2
No ponga un límite superior a sus contraseñas. Los está haciendo hash, no hay razón de almacenamiento para un límite superior. Si le preocupan los ataques DoS utilizando el hash de contraseña, 1000 o 1024 es un límite superior razonable.
Iiridayn
¿Por qué limitar la longitud de la contraseña? Al menos deje que un usuario cree una contraseña de 100 caracteres :)
Andrew
4 caracteres es un límite inferior bastante peligroso para las contraseñas, ya que son triviales para descifrar. Como mínimo, use 8, pero 14 o 16 es mucho mejor.
Quikchange
Esta es una pregunta muy antigua con una respuesta desactualizada. Vea la respuesta de Gilles para estar al día.
kelalaka

Respuestas:

448

Actualización: el simple uso de una función hash no es lo suficientemente fuerte como para almacenar contraseñas. Deberías leer la respuesta de Gilles en este hilo para obtener una explicación más detallada.

Para las contraseñas, use un algoritmo hash de fortalecimiento de claves como Bcrypt o Argon2i. Por ejemplo, en PHP, use la función password_hash () , que usa Bcrypt por defecto.

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

El resultado es una cadena de 60 caracteres similar a la siguiente (pero los dígitos variarán, ya que genera una sal única).

$2y$10$.vGA1O9wmRjrwAVXD98HNOgsNpDczlqm3Jq7KnEd1rVAGv3Fykk1a

Use el tipo de datos SQL CHAR(60) para almacenar esta codificación de un hash Bcrypt. Tenga en cuenta que esta función no codifica como una cadena de dígitos hexadecimales, por lo que no podemos eliminarla fácilmente para almacenarla en binario.

Otras funciones hash todavía tienen usos, pero no para almacenar contraseñas, por lo que conservaré la respuesta original a continuación, escrita en 2008.


Depende del algoritmo de hash que uses. El hash siempre produce un resultado de la misma longitud, independientemente de la entrada. Es típico representar el resultado del hash binario en el texto, como una serie de dígitos hexadecimales. O puede usar la UNHEX()función para reducir una cadena de dígitos hexadecimales a la mitad.

  • MD5 genera un valor hash de 128 bits. Puede usar CHAR (32) o BINARY (16)
  • SHA-1 genera un valor hash de 160 bits. Puede usar CHAR (40) o BINARY (20)
  • SHA-224 genera un valor hash de 224 bits. Puede usar CHAR (56) o BINARY (28)
  • SHA-256 genera un valor hash de 256 bits. Puede usar CHAR (64) o BINARY (32)
  • SHA-384 genera un valor hash de 384 bits. Puede usar CHAR (96) o BINARY (48)
  • SHA-512 genera un valor hash de 512 bits. Puede usar CHAR (128) o BINARY (64)
  • BCrypt genera un valor hash de 448 bits dependiente de la implementación. Es posible que necesite CHAR (56), CHAR (60), CHAR (76), BINARY (56) o BINARY (60)

A partir de 2015, NIST recomienda usar SHA-256 o superior para cualquier aplicación de funciones hash que requiera interoperabilidad. Pero NIST no recomienda el uso de estas funciones simples de hash para almacenar contraseñas de forma segura.

Los algoritmos de hash menores tienen sus usos (como internos a una aplicación, no para intercambio), pero se sabe que son crackeables .

Bill Karwin
fuente
47
@Hippo: Por favor, no uses el nombre de usuario como sal. Genere una sal al azar por usuario.
Bill Karwin
11
Sí, no hay razón para no almacenarlo en la misma fila. Incluso si un atacante obtiene acceso a su base de datos, tendría que construir su tabla de arco iris en función de esa sal. Y eso es tanto trabajo como simplemente adivinar la contraseña.
Bill Karwin
55
@SgtPooki: necesita otra columna para almacenar la sal en texto sin formato. Luego, puede cambiar la contraseña del usuario con la misma sal cuando la escribe y comparar el resultado con el resumen de resumen almacenado en la tabla.
Bill Karwin
12
Si está almacenando la sal en la misma tabla (o en cualquier otra ubicación con los mismos permisos de acceso) no hay razón para no usar el nombre de usuario como sal, ya que será único por usuario. Sin embargo, cualquier sal conocida hace que el hash sea criptográficamente más débil que si no hubiera sal conocida. Una sal solo agrega valor si también es desconocida.
fijiaaron
9
No entiendo el trato con la sal conocida versus la desconocida. Si está implementando un sitio, la sal necesita ser conocida por la página de inicio de sesión / script / servicio que está probando la contraseña. Entonces, ustedes defensores de la sal "desconocidos", ¿están asumiendo que el código para el proceso de inicio de sesión es desconocido para el atacante? De lo contrario, ¿el atacante no siempre sabrá la sal, ya sea aleatoria, única, almacenada junto con la contraseña hash o aparte?
mattstuehler
13

En realidad, puede usar CHAR(longitud de hash) para definir su tipo de datos para MySQL porque cada algoritmo de hash siempre evaluará la misma cantidad de caracteres. Por ejemplo, SHA1siempre devuelve un número hexadecimal de 40 caracteres.

Noah Goodrich
fuente
1
SHA-1 no es adecuado para contraseñas hash.
Gilles 'SO- deja de ser malvado'
10

Utilice siempre un algoritmo de hash de contraseña: Argon2 , scrypt , bcrypt o PBKDF2 .

Argon2 ganó el concurso de hashing de contraseñas de 2015. Scrypt , bcrypt y PBKDF2 son algoritmos más antiguos que ahora se consideran menos preferidos, pero aún son fundamentalmente sólidos, por lo que si su plataforma aún no es compatible con Argon2, está bien usar otro algoritmo por ahora.

Nunca almacene una contraseña directamente en una base de datos. Tampoco lo cifre: de lo contrario, si se viola su sitio, el atacante obtiene la clave de descifrado y puede obtener todas las contraseñas. Las contraseñas DEBEN ser hash .

Un hash de contraseña tiene propiedades diferentes de un hash de tabla hash o un hash criptográfico. Nunca use un hash criptográfico ordinario como MD5, SHA-256 o SHA-512 en una contraseña. Un algoritmo de hash de contraseña utiliza un salt , que es único (no se usa para ningún otro usuario o en la base de datos de nadie). La sal es necesaria para que los atacantes no puedan calcular previamente los valores hash de las contraseñas comunes: con una sal, tienen que reiniciar el cálculo para cada cuenta. Un algoritmo de hash de contraseña es intrínsecamente lento , tan lento como puede permitirse. La lentitud lastima al atacante mucho más que a ti porque el atacante tiene que probar muchas contraseñas diferentes. Para obtener más información, consulte Cómo contraseñas seguras de hash .

Un hash de contraseña codifica cuatro piezas de información:

  • Un indicador de qué algoritmo se utiliza. Esto es necesario para la agilidad : las recomendaciones criptográficas cambian con el tiempo. Debe poder realizar la transición a un nuevo algoritmo.
  • Un indicador de dificultad o dureza. Cuanto mayor sea este valor, más cálculo se necesita para calcular el hash. Esto debería ser un valor de configuración constante o global en la función de cambio de contraseña, pero debería aumentar con el tiempo a medida que las computadoras se vuelven más rápidas, por lo que debe recordar el valor de cada cuenta. Algunos algoritmos tienen un solo valor numérico, otros tienen más parámetros allí (por ejemplo, para ajustar el uso de la CPU y el uso de RAM por separado).
  • La sal. Como la sal debe ser globalmente única, debe almacenarse para cada cuenta. La sal debe generarse aleatoriamente en cada cambio de contraseña.
  • El hash propiamente dicho, es decir, la salida del cálculo matemático en el algoritmo de hash.

Muchas bibliotecas incluyen un par de funciones que convenientemente empaqueta esta información como una sola cadena: una que toma el indicador del algoritmo, el indicador de dureza y la contraseña, genera una sal aleatoria y devuelve la cadena hash completa; y uno que toma una contraseña y la cadena hash completa como entrada y devuelve un booleano que indica si la contraseña era correcta. No hay un estándar universal, pero una codificación común es

$ algoritmo $ parámetros $ salt $ salida

donde algorithmes un número o una cadena alfanumérica corta que codifica la elección del algoritmo, parameterses una cadena imprimible salty outputestá codificada en Base64 sin terminar= .

16 bytes son suficientes para la sal y la salida. (Ver, por ejemplo, recomendaciones para Argon2 .) Codificado en Base64, son 21 caracteres cada uno. Las otras dos partes dependen del algoritmo y los parámetros, pero son típicos de 20 a 40 caracteres. Eso es un total de aproximadamente 82 caracteres ASCII ( CHAR(82)y no es necesario usar Unicode), a lo que debe agregar un margen de seguridad si cree que será difícil ampliar el campo más adelante.

Si codifica el hash en formato binario, puede reducirlo a 1 byte para el algoritmo, 1-4 bytes para la dureza (si codifica algunos de los parámetros) y 16 bytes cada uno para la sal y la salida , para un total de 37 bytes. Digamos 40 bytes ( BINARY(40)) para tener al menos un par de bytes de repuesto. Tenga en cuenta que estos son bytes de 8 bits, no caracteres imprimibles, en particular el campo puede incluir bytes nulos.

Tenga en cuenta que la longitud del hash no tiene ninguna relación con la longitud de la contraseña.

Gilles 'SO- deja de ser malvado'
fuente
9

Puede encontrar este artículo de Wikipedia sobre la salazón que vale la pena . La idea es agregar un conjunto de datos para aleatorizar su valor hash; esto protegerá sus contraseñas de ataques de diccionario si alguien obtiene acceso no autorizado a los hashes de contraseñas.

Dana la sana
fuente
2
De hecho, eso es muy valioso (+1), ¡pero no responde la pregunta! (-1)
Bill Karwin
3
Sí, pero definitivamente relevante en este contexto (+1)
Treb
7

Como una cadena de longitud fija (VARCHAR (n) o como MySQL lo llame). Un hash siempre tiene una longitud fija de, por ejemplo, 12 caracteres (según el algoritmo de hash que utilice). Por lo tanto, una contraseña de 20 caracteres se reduciría a un hash de 12 caracteres, y una contraseña de 4 caracteres también generaría un hash de 12 caracteres.

Treb
fuente
3
'o como MySQL lo llame' - MYSQL lo llama CHAR. Este tipo es para el valor de longitud fija. Así que creo que CHAR es mejor tipo que VARCHAR.
t298712383
4

Debería usar TEXT(almacenar un número ilimitado de caracteres) en aras de la compatibilidad hacia adelante. Los algoritmos de hash (deben) fortalecerse con el tiempo y, por lo tanto, este campo de la base de datos deberá admitir más caracteres con el tiempo. Además, dependiendo de su estrategia de migración, es posible que necesite almacenar hashes nuevos y antiguos en el mismo campo, por lo que no se recomienda fijar la longitud a un tipo de hash.

bart
fuente
3

Realmente depende del algoritmo de hash que estés usando. La longitud de la contraseña tiene poco que ver con la longitud del hash, si no recuerdo mal. Busque las especificaciones del algoritmo de hash que está utilizando, ejecute algunas pruebas y trunca justo por encima de eso.

willasaywhat
fuente
3

Los hashes son una secuencia de bits (128 bits, 160 bits, 256 bits, etc., según el algoritmo). Su columna debe ser de tipo binario, no de texto / caracteres, si MySQL lo permite (el tipo de datos de SQL Server es binary(n)o varbinary(n)). También debes salar los hash. Las sales pueden ser de texto o binarias, y necesitará una columna correspondiente.

Yfeldblum
fuente
La justicia es completamente correcta aquí: MySQL los almacenará como valores numéricos y hará que la búsqueda en esta columna sea mucho más eficiente que hacer una coincidencia de cadenas, sin embargo, las sales no deben almacenarse en la base de datos junto a los datos salados, lo que elimina la seguridad que proporcionan las sales. .
Tony Maro
66
Las sales no son secretas. El único secreto es la contraseña. Solo asegúrese de que cada nueva contraseña obtenga una nueva sal. Cada vez que el usuario cambia su contraseña, el sistema debe generar una nueva sal para esa contraseña. Las sales deben ser largas y aleatorias, como 16 bytes generados a partir de un PRNG criptográficamente seguro.
yfeldblum
1
@TonyMaro No estoy seguro de si una cadena de contraseña coincidente en el nivel SQL es una buena estrategia. En otras palabras, no debe buscar una contraseña en su base de datos, en su lugar, recuperar al usuario en función de su nombre de usuario y comparar las contraseñas en código, en lugar de SQL.
bart
1

Siempre probé para encontrar la longitud MÁXIMA de una cadena encriptada y establecerla como la longitud de caracteres de un tipo VARCHAR. Dependiendo de cuántos registros va a tener, realmente podría ayudar al tamaño de la base de datos.

Stephen Walcher
fuente
0

para md5 vARCHAR (32) es apropiado. Para aquellos que usan AES, mejor usar varbinary.

Liebre Srinivasa
fuente
1
Ni MD5 ni AES son adecuados o tienen una contraseña.
Gilles 'SO- deja de ser malvado'