Anteriormente vimos cómo generar una contraseña segura en Python cuando necesitamos un token o una clave segura, ahora veremos cómo hashear una contraseña en Python, usando bcrypt.
El algoritmo de bcrypt es usado también por PHP al hashear contraseñas. Igualmente está disponible en Go.
Hashear contraseñas es un estándar que debemos seguir al implementar autenticación de usuarios, por ejemplo. Pero bueno, vamos al tutorial en donde veremos:
Para esto, primero debes instalar Python y pip. Una vez que lo tengas, ejecuta:
pip install bcrypt
Con eso tenemos. Hora de hashear contraseñas.
Este es el código necesario para hashear una contraseña:
""" Ejemplo para hashear y comprobar contraseñas en Python usando bcrypt @author parzibyte """ import bcrypt # Esta puede venir de un formulario, ser leída con input o cualquier cosa pass_texto_plano = "hunter2" # Debemos tenerla como bytes pass_texto_plano = pass_texto_plano.encode() # La sal, necesaria para preparar nuestra contraseña sal = bcrypt.gensalt() # Hashear pass_hasheada = bcrypt.hashpw(pass_texto_plano, sal)
Aquí vemos una cosa importante, y es que la contraseña debe estar como bytes, no como una cadena. Para ello, usamos el método encode
de las strings.
Si almacenas la contraseña hasheada y luego la recuperas como string, recuerda convertirla. Igualmente, la contraseña en texto plano debe estar convertida en bytes.
Ahora supongamos que ya guardaste ese hash, para comprobarlo llamamos a bcrypt.checkpw de la siguiente manera:
bcrypt.checkpw(pass_texto_plano, pass_hasheada)
El orden de los parámetros es importante. Primero le pasamos la contraseña en texto plano, y luego el hash que tenemos almacenado por ahí. Recuerda que antes de esto debes convertirlos a bytes.
Un ejemplo simple que puedes probar para hashear y comprobar contraseñas en Python, es el siguiente:
""" Ejemplo para hashear y comprobar contraseñas en Python usando bcrypt @author parzibyte """ import bcrypt # Esta puede venir de un formulario, ser leída con input o cualquier cosa pass_texto_plano = "hunter2" # Debemos tenerla como bytes pass_texto_plano = pass_texto_plano.encode() # La sal, necesaria para preparar nuestra contraseña sal = bcrypt.gensalt() # Hashear pass_hasheada = bcrypt.hashpw(pass_texto_plano, sal) #Nota: en casos reales no imprimas ni guardes en un log las contraseñas ni la sal print("La contraseña en texto plano es '{}', la sal es '{}' y la hasheada es '{}'".format(pass_texto_plano, sal, pass_hasheada)) # Ahora vamos a comprobarla, recuerda que pass_hasheada puede provenir de tu base de datos o un lugar en donde la guardaste print("Comprobando contraseñas...") if bcrypt.checkpw(pass_texto_plano, pass_hasheada): print("Ok, las contraseñas coinciden") else: print("Contraseña incorrecta")
Recuerda que en la práctica no debes guardar las contraseñas en otro lugar más que en tu base de datos o el lugar en donde van a residir, nada de logs.
Si ejecutas el programa varias veces, verás que aparece una contraseña hasheada distinta, aunque en texto plano es igual. Esa es la ventaja de hashearlas y no de simplemente encriptarlas a través de SHA o esas cosas.
Estos algoritmos son un poco complejos, pero además, lentos. Y esa lentitud es intencional, para evitar ataques de fuerza bruta. Hay una cosa que se llama costo o factor de trabajo, y se refiere en palabras simples a qué tanto de tiempo se lleva hashear y comprobar una contraseña.
Entre mayor costo, más tardado y más seguro. Entre menor, lo contrario. En un escenario perfecto pondríamos el costo al máximo, pero no, porque afecta el rendimiento.
Por defecto, el costo es de 12 pero podemos cambiarlo al generar la sal, así (en ese caso le cambiamos a 16, igualmente podría ser menor):
bcrypt.gensalt(16)
Ten cuidado con ese costo, si lo pones muy alto y tu hardware no es tan potente, será muy tardado. Recomiendo dejarlo como está.
Este método de hasheo de contraseñas tiene un límite de 72 caracteres, pero no te preocupes, puedes pasar la contraseña a sha256 y luego a base64 (recuerdo que en PHP era con md5 y funcionaba bien) como lo recomiendan en la documentación.
Para hacerlo, llamamos a sha256
y el resultado se lo pasamos a base64encode
; más tarde eso es lo que encriptamos.
No te preocupes, no hay riesgo de seguridad y de esta manera evitas poner un límite a la contraseña, aunque no por eso vas a dejar de validar.
Este proceso de convertirlo a sha256 y luego a base64 debes hacerlo igualmente cuando recibas la contraseña del usuario y la compruebes.
Hay otros algoritmos más recientes, pero este funciona bastante bien. Al final de todo, es elección de cada desarrollador. Otro método del que he escuchado es scrypt, pero será tema de otro post.
Te invito a ver la documentación oficial de este paquete de bcrypt para Python, justo aquí.
Ya te enseñé cómo convertir una aplicación web de Vue 3 en una PWA. Al…
En este artículo voy a documentar la arquitectura que yo utilizo al trabajar con WebAssembly…
En un artículo anterior te enseñé a crear un PWA. Al final, cualquier aplicación que…
Al usar Comlink para trabajar con los workers usando JavaScript me han aparecido algunos errores…
En este artículo te voy a enseñar cómo usar un "top level await" esperando a…
Ayer estaba editando unos archivos que son servidos con el servidor Apache y al visitarlos…
Esta web usa cookies.