Se supone que este código usa un hash en una contraseña. La sal y la contraseña hash se están guardando en la base de datos. La contraseña en sí no lo es.
Dada la naturaleza delicada de la operación, quería asegurarme de que todo fuera kosher.
import hashlib
import base64
import uuid
password = 'test_password'
salt = base64.urlsafe_b64encode(uuid.uuid4().bytes)
t_sha = hashlib.sha512()
t_sha.update(password+salt)
hashed_password = base64.urlsafe_b64encode(t_sha.digest())
t_sha.digest() + salt
. Puede dividir la sal nuevamente más tarde cuando haya decodificado la contraseña hash con sal, ya que sabe que la contraseña hash decodificada tiene exactamente 32 bytes.secrets
.Respuestas:
EDITAR: Esta respuesta es incorrecta. Una sola iteración de SHA512 es rápida , lo que la hace inapropiada para su uso como función hash de contraseña. Utilice una de las otras respuestas aquí en su lugar.
Se ve bien para mí. Sin embargo, estoy bastante seguro de que en realidad no necesitas base64. Podrías hacer esto:
import hashlib, uuid salt = uuid.uuid4().hex hashed_password = hashlib.sha512(password + salt).hexdigest()
Si no crea dificultades, puede obtener un almacenamiento un poco más eficiente en su base de datos almacenando la sal y la contraseña hash como bytes sin procesar en lugar de cadenas hexadecimales. Para hacerlo, reemplace
hex
conbytes
yhexdigest
condigest
.fuente
salt
está almacenado en la base de datos y también en la contraseña hash salada.Basado en las otras respuestas a esta pregunta, he implementado un nuevo enfoque usando bcrypt.
Por que usar bcrypt
Si he entendido bien, el argumento para utilizar
bcrypt
sobreSHA512
es quebcrypt
está diseñado para ser lento.bcrypt
también tiene una opción para ajustar qué tan lento desea que sea al generar la contraseña hash por primera vez:# The '12' is the number that dictates the 'slowness' bcrypt.hashpw(password, bcrypt.gensalt( 12 ))
Lento es deseable porque si una parte malintencionada pone sus manos en la tabla que contiene contraseñas hash, entonces es mucho más difícil forzarlas.
Implementación
def get_hashed_password(plain_text_password): # Hash a password for the first time # (Using bcrypt, the salt is saved into the hash itself) return bcrypt.hashpw(plain_text_password, bcrypt.gensalt()) def check_password(plain_text_password, hashed_password): # Check hashed password. Using bcrypt, the salt is saved into the hash itself return bcrypt.checkpw(plain_text_password, hashed_password)
Notas
Pude instalar la biblioteca con bastante facilidad en un sistema Linux usando:
Sin embargo, tuve más problemas para instalarlo en mis sistemas Windows. Parece que necesita un parche. Vea esta pregunta de desbordamiento de pila: py-bcrypt instalando en win 7 64bit python
fuente
py-bcrypt
Comentario al margen : parece que es el antiguo paquete pypi y desde entonces se le ha cambiado el nombre abcrypt
.Lo inteligente es no escribir la criptografía usted mismo, sino usar algo como passlib: https://bitbucket.org/ecollins/passlib/wiki/Home
Es fácil estropear la escritura de su código criptográfico de forma segura. Lo malo es que con un código que no es criptográfico, a menudo lo nota inmediatamente cuando no está funcionando, ya que su programa falla. Mientras que con el código criptográfico, a menudo solo se entera después de que es demasiado tarde y sus datos se han visto comprometidos. Por lo tanto, creo que es mejor usar un paquete escrito por otra persona que tenga conocimientos sobre el tema y que esté basado en protocolos probados en batalla.
Además, passlib tiene algunas características agradables que lo hacen fácil de usar y también fácil de actualizar a un protocolo de hash de contraseña más nuevo si se rompe un protocolo antiguo.
Además, una sola ronda de sha512 es más vulnerable a los ataques de diccionario. sha512 está diseñado para ser rápido y esto es realmente algo malo cuando se intenta almacenar contraseñas de forma segura. Otras personas han pensado mucho en este tipo de cuestiones, así que es mejor que aproveches esto.
fuente
hashlib
es para funciones hash criptográficas.passlib
es para almacenar contraseñas de forma segura. No son lo mismo (aunque mucha gente parece pensar que sí ... y luego se descifran las contraseñas de sus usuarios).passlib
genera su propia sal, que se almacena en la cadena hash devuelta (al menos para ciertos esquemas como BCrypt + SHA256 ), por lo que no debe preocuparse por eso.Para que esto funcione en Python 3, necesitará codificar UTF-8, por ejemplo:
hashed_password = hashlib.sha512(password.encode('utf-8') + salt.encode('utf-8')).hexdigest()
De lo contrario, obtendrá:
fuente
A partir de Python 3.4, el
hashlib
módulo de la biblioteca estándar contiene funciones de derivación de claves que están "diseñadas para el cifrado seguro de contraseñas" .Entonces use uno de esos, como
hashlib.pbkdf2_hmac
, con una sal generada usandoos.urandom
:from typing import Tuple import os import hashlib import hmac def hash_new_password(password: str) -> Tuple[bytes, bytes]: """ Hash the provided password with a randomly-generated salt and return the salt and hash to store in the database. """ salt = os.urandom(16) pw_hash = hashlib.pbkdf2_hmac('sha256', password.encode(), salt, 100000) return salt, pw_hash def is_correct_password(salt: bytes, pw_hash: bytes, password: str) -> bool: """ Given a previously-stored salt and hash, and a password provided by a user trying to log in, check whether the password is correct. """ return hmac.compare_digest( pw_hash, hashlib.pbkdf2_hmac('sha256', password.encode(), salt, 100000) ) # Example usage: salt, pw_hash = hash_new_password('correct horse battery staple') assert is_correct_password(salt, pw_hash, 'correct horse battery staple') assert not is_correct_password(salt, pw_hash, 'Tr0ub4dor&3') assert not is_correct_password(salt, pw_hash, 'rosebud')
Tenga en cuenta que:
os.urandom
siempre utiliza una fuente de aleatoriedad criptográficamente segurahmac.compare_digest
, utilizado enis_correct_password
, es básicamente el==
operador de cadenas pero sin la capacidad de cortocircuito, lo que lo hace inmune a los ataques de sincronización. Eso probablemente no proporciona ningún valor de seguridad adicional , pero tampoco hace daño, así que seguí adelante y lo usé.Para obtener una teoría sobre lo que hace un buen hash de contraseña y una lista de otras funciones apropiadas para usar el hash de contraseñas, consulte https://security.stackexchange.com/q/211/29805 .
fuente
passlib parece ser útil si necesita usar hashes almacenados por un sistema existente. Si tiene el control del formato, use un hash moderno como bcrypt o scrypt. En este momento, bcrypt parece ser mucho más fácil de usar desde Python.
passlib admite bcrypt, y recomienda instalar py-bcrypt como backend: http://pythonhosted.org/passlib/lib/passlib.hash.bcrypt.html
También puede usar py-bcrypt directamente si no desea instalar passlib. El archivo Léame tiene ejemplos de uso básico.
ver también: Cómo usar scrypt para generar hash para contraseña y sal en Python
fuente
No quiero resucitar un hilo antiguo, pero ... cualquiera que quiera usar una solución segura moderna y actualizada, use argon2.
https://pypi.python.org/pypi/argon2_cffi
Ganó el concurso de hash de contraseñas. ( https://password-hashing.net/ ) Es más fácil de usar que bcrypt y es más seguro que bcrypt.
fuente
Primero importar: -
import hashlib, uuid
Luego cambie su código de acuerdo con esto en su método:
uname = request.form["uname"] pwd=request.form["pwd"] salt = hashlib.md5(pwd.encode())
Luego, pase este salt y uname en la consulta SQL de su base de datos, debajo del inicio de sesión hay un nombre de tabla:
sql = "insert into login values ('"+uname+"','"+email+"','"+salt.hexdigest()+"')"
fuente