Directrices

Almacenamiento de contraseñas

Si su aplicación autentica usuarios, lo más probable es que también tenga que tratar con contraseñas.

Manejar las contraseñas de los usuarios es un asunto realmente importante, y manejarlas adecuadamente lo es aún más. 

Es difícil imaginar un escenario peor que el de una aplicación atacada y las contraseñas de los usuarios filtradas por Internet a la vista de todos. Personalmente, nos estremecemos al pensarlo. Entonces, ¿cómo pueden almacenarse las contraseñas de forma segura y de acuerdo con las mejores prácticas? Veamos algunas formas. 

Cifrado frente a hashing

En un nivel superficial, uno podría pensar que el cifrado suena como una solución decente para el almacenamiento seguro de contraseñas, sin embargo, confiar totalmente en él podría ser algo problemático. 

El cifrado es intrínsecamente una función bidireccional que, por supuesto, significa que al igual que se puede cifrar una contraseña, también se puede descifrar. Perfectamente lógico, ¿verdad? De lo contrario, ¿cómo se podría validar si la contraseña de un usuario coincide con la almacenada en la base de datos? 

Por lo tanto, la capacidad de descifrar contraseñas es también una gran responsabilidad. Si alguien compromete un servidor y consigue el texto cifrado de una contraseña, es muy probable que también consiga el material clave necesario para descifrar esas contraseñas.

Por otro lado, el hashing es mucho más adecuado para las contraseñas debido a su naturaleza unidireccional. Una vez que se ha cifrado algo, no existe ninguna función para convertir directamente el texto cifrado en el texto sin formato original. Esta propiedad hace que los hashes sean especialmente adecuados para la protección de contraseñas. 

No todos los hash son iguales

Una vez que te hayas decidido por el hash de contraseñas para su almacenamiento, tampoco es tan sencillo como aplicar una función hash y listo. 

Hay hash de todas las formas y tamaños, la mayoría de los cuales no son precisamente adecuados para almacenar contraseñas, dados todos los avances de la tecnología informática en la última década. 

Como se mencionó anteriormente, los hash no se pueden revertir debido a que son una función unidireccional. Si bien esto es técnicamente cierto, los hash también son deterministas, lo que significa que también son susceptibles a las tácticas de fuerza bruta que pueden permitir a un atacante revertir potencialmente un hash al texto plano original con el tiempo y los recursos suficientes.

Por este motivo, dividimos las funciones hash en dos categorías:

  • Hashes criptográficos
  • Contraseñas hash
Característica Hash criptográfico Contraseña hash
Velocidad Muy rápido Intencionadamente lento
Factor de trabajo ajustable No

Una característica clave de los hash de contraseñas es que tienen un "factor de trabajo" (ya sea mediante un único número entero, o múltiples parámetros) que define la cantidad de esfuerzo que se necesita para calcular el hash. 

A medida que las CPU y GPU se han hecho más rápidas con el paso de los años, se ha hecho más fácil realizar ataques masivos de fuerza bruta contra hashes en hardware de consumo, lo que implica que un hash puede volverse cada vez menos seguro con el tiempo. 

El "factor de trabajo" se utiliza para garantizar que los hashes se almacenan siguiendo las tendencias del sector. A medida que el hardware se hace más rápido, se aumenta el factor de trabajo del algoritmo para garantizar que el hash tarda más tiempo y esfuerzo en descifrarse. Digamos, como ejemplo, 100ms en hardware contemporáneo. 

Esto significa que, en la práctica, puede ser necesario aumentar el factor trabajo cada 2-3 años.

Hash criptográfico Contraseña hash
MD5 bcrypt
SHA-1 scrypt
SHA-2 PBKDF2
SHA-3 Argón2