El día de hoy te voy a compartir un poco de mi experiencia como programador al guardar contraseñas en bases de datos, sin importar lenguaje de programación ni motor de base de datos.
Te daré algunos consejos para almacenar passwords en una base de datos y que obviamente queden seguras para que ni siquiera tú sepas cuál es la contraseña pero puedas resetearla en caso de ser necesario.
Resumen
Si no quieres leer todo el post y quieres ir al grano, mi recomendación final es que uses bcrypt y te fijes en la longitud límite de ese algoritmo.
Hay varias implementaciones en cada lenguaje de programación, por ejemplo Python, Golang, PHP y Node.js.
Si tú usas otro lenguaje de programación entonces solo es cuestión de buscar el equivalente o la implementación en ese lenguaje.
Las vulnerabilidades de toda contraseña
Toda contraseña puede ser adivinada usando ataques de fuerza bruta. Ninguna se salva. Con el tiempo y poder computacional suficiente se puede “adivinar” cualquier contraseña.
Lo que podemos hacer como programadores es obligar al usuario a que elija contraseñas aleatorias, largas y que combinen caracteres así como usar el método adecuado para almacenarlas.
Tampoco es para asustarse. Una buena contraseña tardaría miles de años en adivinarse usando el poder computacional actual, pero repito, con el tiempo suficiente es posible.
Por otro lado podemos combinar esas contraseñas con más factores como enviar un SMS, enviar un código al correo, leer la huella, etcétera.
Nunca uses texto plano
Aunque no tengas nada de experiencia, nunca uses texto plano para guardarlas. Mejor investiga o sigue leyendo este post, pero nunca, jamás guardes contraseñas en texto plano.
Recuerda que algunos usuarios no son responsables y usan la misma contraseña para todo, lo que haría que si alguien ve la contraseña en tu sistema pueda usarla en varios lugares.
Entonces por regla general, nunca se debe guardar la contraseña tal y como el usuario la ha escrito.
Por cierto, si usas formularios en la web usa el método POST y HTTPS.
Tampoco uses md5, sha, etcétera
He visto que varias personas utilizan métodos para calcular la suma de verificación y no para hashear una contraseña.
Este método es mejor que el texto plano, pero igual de inseguro y no deberías usarlo al menos por sí solo.
El problema con md5 y funciones de suma de verificación
Las funciones checksum o de suma de verificación calculan la suma de verificación de algo, y el resultado es irreversible. Todo bien hasta ahí.
Usaré el ejemplo de sha256 para lo siguiente (y por cierto, aunque sea SHA65536, eso no lo hace más seguro) y también la contraseña 123
.
Al calcular la suma de verificación, la salida es a665a45920422f9d417e4867efdc4fb8a04a1f3fff1fa07e998e86f7f7a27ae3
.
Eso está perfecto, porque el atacante no puede revertir esa suma de verificación. Es imposible por diseño; esa función simplemente no puede ser revertida. ¿Pero qué pasa si el atacante sabe todas las sumas de verificación de todas las contraseñas previamente?
Ya existen tablas (rainbow tables) que tienen la contraseña en texto plano y su suma de verificación. De hecho en la imagen de arriba acabo de usar un sitio que ofrece ese servicio.
Entonces, teniendo el suficiente poder computacional, paciencia, motor de base de datos altamente rápido y la suma de verificación podremos dar con el texto original que originó esa suma de verificación.
Las sumas de verificación no son tan malas
Ahora bien, tampoco vamos a exagerar. Si el usuario elige una contraseña segura y guardas su suma de verificación, es poco probable que esa contraseña ya exista en una tabla.
En el ejemplo de arriba se pudo crackear fácilmente porque 123
es una de las más usadas, pero si el usuario elige algo como &NFu&ZlpTWi%Kq^%^6Ws#aczc7r*o9ya632VNzNuXZB^5@6!ATPtYvPw2Iuej&aRmgOlQ1Z^*EpSZZuKj7hSi&4$udC698mCUQW
cuya suma de verificación es f49b94a07cdf579349f322fee400c7bfd6a3e7389860b4371ed032c7cadfe6b4
es muy poco probable que exista en una tabla.
Incluso así, toma en cuenta lo siguiente:
- Se pueden generar sumas de verificación de todas las posibles contraseñas, o al menos de contraseñas de cierta longitud
- Por lo general el usuario no va a elegir contraseñas seguras. Es tu responsabilidad proteger su contraseña aunque sea 123
- Si varios usuarios eligen la misma contraseña, la suma de verificación resultante será la misma.
- Si te roban tu base de datos con varias contraseñas, el atacante va a obtener la mayoría de contraseñas fáciles
Yo sigo sin recomendar este método, pero es importante ver lo que tiene de bueno y lo que tiene de malo.
Te repito: no recomiendo este método. Mejor sigue leyendo para ver un método más seguro.
De hecho las sumas de verificación son para eso: verificar el contenido de algo, y no para contraseñas (por ejemplo, para revisar que te has descargado algo y que no ha sido modificado durante el transporte).
Vamos a ver un método creado específicamente para contraseñas.
Usando bcrypt
Antes de que lo olvide: bcrypt es un ejemplo del método usado. Yo lo uso en todos mis sistemas, pero si tú quieres usar una alternativa hazlo, solo asegúrate de que el algoritmo o paradigma sean el mismo.
Bcrypt es un método de un solo camino, es decir, simplemente no es reversible.
La diferencia con los métodos de suma de verificación es que éste agrega una sal, así que no se puede crackear usando tablas.
- Por ejemplo, al hashear 123 la salida es:
$2y$10$11sLNzkm/plAJPzY4R.QbOBVRLzNJH6rxzG2rjCy2mm7aXWFWVPHq
- Si lo hago de nuevo, la salida es
$2y$10$bfkS3tEJr4ODPQ9ISC.PZekjHZBBr44/QBBMETbF8kIMOWzEi2A26
Cada vez que lo haga, aparecerá un hash nuevo aunque la entrada sea la misma.
Por otro lado, si te fijas, los hashes tienen un $10
después del $2y
, ese es el costo o el número de rondas que se hace para hashear esa contraseña.
Con el tiempo (cuando las computadoras sean más rápidas) eso se puede hacer más grande, haciendo mucho más lento el ataque por fuerza bruta y prácticamente inviable el ataque con tablas.
Entonces bcrypt es la respuesta. bcrypt es la clave, es uno de los mejores métodos para almacenar contraseñas. Y entre más alto sea el costo, más protegido estarás.
Vídeo explicativo
Si quieres profundizar un poco más, puedes ver el siguiente vídeo:
Conclusión y notas finales
Algunos recomiendan combinar las funciones de suma de verificación con bcrypt, así permites que el usuario utilice contraseñas más largas que el límite de bcrypt, pero le quitas entropía a su contraseña ya que las sumas de verificación normalmente se muestran en hexadecimal y solo usan a-f y 0-9.
Como sea, en conclusión yo te recomiendo usar simplemente bcrypt y ya está. Solo ten en cuenta el límite de la longitud.
Y como siempre, si tú crees que usar otro método está bien para ti, lo respeto. Yo solo te comparto mis pensamientos y experiencia.