2017-01-03 1 views
0

Je suis en train de créer un système d'enregistrement pour mon application Web dans lequel les utilisateurs fournissent un nom d'utilisateur et un mot de passe. Ces données sont stockées dans une base de données postgresql. J'utilise bcrypt pour générer un hachage salé de l'utilisateur mot de passe entré comme suitComment récupérer des mots de passe à partir d'une base de données

import bcrypt 
hashed = bcrypt.hashpw(PasswordFromWebForm.encode('UTF-8'), bcrypt.gensalt()) 

Cela crée un mot de passe salé qui ressemble à quelque chose comme ça - b'$2b$12$GskbcRCMFHGuXumrNt3FLO'

je stocke cette valeur dans une base de données postgresql. Ensuite, lorsqu'un utilisateur tente de se connecter au système, je souhaite vérifier ses informations d'identification. Pour ce faire, j'ai l'intention de faire quelque chose dans le sens de -

import psycopg2 
conn = psycopg2.connect("dbname=test user=me") 
cur = conn.cursor() 

saltedpassword = cur.execute("SELECT saltedpassword FROM test WHERE loginid = %s", (LoginIDFromWebForm,)) 

if bcrypt.hashpw(PasswordFromWebForm.encode('UTF-8'), saltedpassword) == saltedpassword: 
    print("Success") 

Cela ne fonctionne pas. Il renvoie l'erreur TypeError: Unicode-objects must be encoded before hashing suivante.

Je soupçonne que cette erreur est parce que la saltedpassword variables stocke la valeur comme une chaîne comme celui-ci "b'$2b$12$GskbcRCMFHGuXumrNt3FLO'" au lieu de simplement b'$2b$12$GskbcRCMFHGuXumrNt3FLO' ordinaire (Notez les guillemets entourant le mot de passe salé dans l'ancienne)

Comment puis-je obtenir autour de cette problème? Quelle est la meilleure façon de stocker le mot de passe haché salé dans une base de données et comment puis-je récupérer le mot de passe lorsque cela est nécessaire pour la vérification? Toutes mes excuses pour la question plutôt longue - aidez svp.

Répondre

2

psycopg2 stocke Unicode texte, vous devez décoder le mot de passe avant de l'insérer dans salé la base de données:

cur.execute("INSERT INTO test VALUES (%s, %s)", 
      (LoginIDFromWebForm, saltedpassword.decode('ascii'))) 

Cela empêche l'être inséré à la place conversion str() (vous donnant "b'....'" dans la base de données).

Ensuite, lors de l'interrogation saltedpassword n'est pas une chaîne, car cursor.execute() ne renvoie pas les résultats; il renvoie None à la place.

Vous devez fetch the result row:

cur.execute("SELECT saltedpassword FROM test WHERE loginid = %s", (LoginIDFromWebForm,)) 
row = cur.fetchone() 
if not row: 
    # No such login ID, handle accordingly 
saltedpassword = row[0].encode('ascii') 

Comme lignes contiennent du texte Unicode, vous devez d'abord encode à un bytestring avant de passer à bcrypt. Vous voulez également utiliser la fonction bcrypt.checkpw() pour vérifier le mot de passe:

if bcrypt.checkpw(PasswordFromWebForm.encode('UTF-8'), saltedpassword): 
    print("Success") 

bcrypt.checkpw() évite timing attacks lorsque l'on compare les chaînes, quelque chose que votre code est vulnérable.

+1

En toute justice, les docs bcrypt vérifient le mot de passe en utilisant 'si bcrypt.hashpw (mot de passe, haché) == hashed' - https://pypi.python.org/pypi/bcrypt/2.0.0 – slim

+1

@slim: voir la documentation mise à jour pour bcrypt 3: https://pypi.python.org/pypi/bcrypt/3.1.2, 'checkpw()' a été ajoutée en 3.1.0. –

+1

Ah oui, juste vu que :) – slim