Ce code est censé hacher un mot de passe avec un sel. Le sel et le mot de passe haché sont enregistrés dans la base de données. Le mot de passe lui-même ne l'est pas.
Étant donné le caractère sensible de l'opération, je voulais m'assurer que tout était casher.
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
. Vous pouvez séparer à nouveau le sel plus tard lorsque vous avez décodé le mot de passe de hachage salé, car vous savez que le mot de passe haché décodé est exactement de 32 octets.secrets
place ne coûte rien .Réponses:
EDIT: Cette réponse est fausse. Une seule itération de SHA512 est rapide , ce qui le rend inapproprié pour une utilisation en tant que fonction de hachage de mot de passe. Utilisez plutôt l'une des autres réponses ici.
Ça me va. Cependant, je suis sûr que vous n'avez pas besoin de base64. Vous pouvez simplement faire ceci:
import hashlib, uuid salt = uuid.uuid4().hex hashed_password = hashlib.sha512(password + salt).hexdigest()
Si cela ne crée pas de difficultés, vous pouvez obtenir un stockage légèrement plus efficace dans votre base de données en stockant le salt et le mot de passe haché sous forme d'octets bruts plutôt que de chaînes hexadécimales. Pour ce faire, remplacez
hex
parbytes
ethexdigest
pardigest
.la source
salt
est stocké dans la base de données et le mot de passe haché salé aussi.Sur la base des autres réponses à cette question, j'ai implémenté une nouvelle approche utilisant bcrypt.
Pourquoi utiliser bcrypt
Si je comprends bien, l'argument d'utiliser
bcrypt
plusSHA512
quebcrypt
est conçu pour être lent.bcrypt
a également une option pour ajuster la vitesse à laquelle vous voulez qu'il soit lors de la génération du mot de passe haché pour la première fois:# The '12' is the number that dictates the 'slowness' bcrypt.hashpw(password, bcrypt.gensalt( 12 ))
La lenteur est souhaitable car si une partie malveillante met la main sur la table contenant des mots de passe hachés, il est beaucoup plus difficile de les forcer brutalement.
la mise en oeuvre
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)
Remarques
J'ai pu installer la bibliothèque assez facilement dans un système Linux en utilisant:
Cependant, j'ai eu plus de mal à l'installer sur mes systèmes Windows. Il semble avoir besoin d'un patch. Voir cette question Stack Overflow: installation de py-bcrypt sur win 7 64 bits python
la source
py-bcrypt
soit l'ancien package pypi et qu'il a depuis été renommébcrypt
.La chose intelligente n'est pas d'écrire la crypto vous-même mais d'utiliser quelque chose comme passlib: https://bitbucket.org/ecollins/passlib/wiki/Home
Il est facile de gâcher l'écriture de votre code cryptographique de manière sécurisée. Ce qui est désagréable, c'est qu'avec un code non crypté, vous le remarquez souvent immédiatement lorsqu'il ne fonctionne pas depuis que votre programme se bloque. Alors qu'avec le code crypto, vous ne le découvrez souvent qu'après qu'il est trop tard et que vos données ont été compromises. Par conséquent, je pense qu'il est préférable d'utiliser un package écrit par quelqu'un d'autre qui connaît le sujet et qui est basé sur des protocoles testés au combat.
Passlib a également quelques fonctionnalités intéressantes qui le rendent facile à utiliser et aussi facile à mettre à niveau vers un protocole de hachage de mot de passe plus récent si un ancien protocole s'avère défectueux.
De plus, un seul cycle de sha512 est plus vulnérable aux attaques par dictionnaire. sha512 est conçu pour être rapide et c'est en fait une mauvaise chose lorsque vous essayez de stocker des mots de passe en toute sécurité. D'autres personnes ont longuement réfléchi à tous ces problèmes, vous feriez mieux d'en profiter.
la source
hashlib
est pour les fonctions de hachage cryptographique.passlib
est pour stocker en toute sécurité les mots de passe. Ce n'est pas la même chose (bien que beaucoup de gens semblent le penser ... et ensuite les mots de passe de leurs utilisateurs sont déchiffrés).passlib
génère son propre sel, qui est stocké dans la chaîne de hachage retournée (au moins pour certains schémas tels que BCrypt + SHA256 ) - vous n'avez donc pas à vous en soucier.Pour que cela fonctionne dans Python 3, vous devrez encoder UTF-8 par exemple:
hashed_password = hashlib.sha512(password.encode('utf-8') + salt.encode('utf-8')).hexdigest()
Sinon, vous obtiendrez:
la source
Depuis Python 3.4, le
hashlib
module de la bibliothèque standard contient des fonctions de dérivation de clé qui sont «conçues pour un hachage de mot de passe sécurisé» .Utilisez donc l'un de ceux-ci, comme
hashlib.pbkdf2_hmac
, avec un sel généré en utilisantos.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')
Notez que:
os.urandom
utilise toujours une source aléatoire sécurisée par cryptographiehmac.compare_digest
, utilisé dansis_correct_password
, est fondamentalement juste l'==
opérateur pour les chaînes, mais sans la capacité de court-circuit, ce qui le rend immunisé contre les attaques de synchronisation. Cela ne fournit probablement pas vraiment de valeur de sécurité supplémentaire , mais cela ne fait pas de mal non plus, alors je suis allé de l'avant et je l'ai utilisé.Pour la théorie sur ce qui fait un bon hachage de mot de passe et une liste d'autres fonctions appropriées pour le hachage des mots de passe avec, voir https://security.stackexchange.com/q/211/29805 .
la source
passlib semble être utile si vous devez utiliser des hachages stockés par un système existant. Si vous avez le contrôle du format, utilisez un hachage moderne comme bcrypt ou scrypt. Pour le moment, bcrypt semble être beaucoup plus facile à utiliser à partir de python.
passlib prend en charge bcrypt et recommande d'installer py-bcrypt en tant que backend: http://pythonhosted.org/passlib/lib/passlib.hash.bcrypt.html
Vous pouvez également utiliser py-bcrypt directement si vous ne souhaitez pas installer passlib. Le readme contient des exemples d'utilisation de base.
voir aussi: Comment utiliser scrypt pour générer un hachage pour le mot de passe et le sel en Python
la source
Je ne veux pas ressusciter un ancien thread, mais ... quiconque souhaite utiliser une solution sécurisée moderne et à jour utilise argon2.
https://pypi.python.org/pypi/argon2_cffi
Il a remporté le concours de hachage de mot de passe. ( https://password-hashing.net/ ) Il est plus facile à utiliser que bcrypt, et il est plus sécurisé que bcrypt.
la source
Importez d'abord: -
import hashlib, uuid
Puis changez votre code en fonction de ceci dans votre méthode:
uname = request.form["uname"] pwd=request.form["pwd"] salt = hashlib.md5(pwd.encode())
Ensuite, passez ce salt et uname dans votre requête SQL de base de données, sous login se trouve un nom de table:
sql = "insert into login values ('"+uname+"','"+email+"','"+salt.hexdigest()+"')"
la source