I am building a registration system for my web application wherein users provide a username and a password. This data is stored in a postgresql database. I am using bcrypt to generate a salted hash of the user entered password as follows
import bcrypt
hashed = bcrypt.hashpw(PasswordFromWebForm.encode('UTF-8'), bcrypt.gensalt())
This creates a salted password that looks something like this - b'$2b$12$GskbcRCMFHGuXumrNt3FLO'
I am storing this value in a postgresql database. Next, when a user tries to login to the system, I want to verify his/her credentials. To do this, I intend to do something along the lines of -
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")
This does not work. It throws the following TypeError: Unicode-objects must be encoded before hashing error.
I suspect that this error is because the variable saltedpassword stores the value as a string like this "b'$2b$12$GskbcRCMFHGuXumrNt3FLO'" instead of just plain b'$2b$12$GskbcRCMFHGuXumrNt3FLO' (Notice the quotes enclosing the salted password in the former)
How do I get around this problem? What is the best way to store the salted hashed password in a database and how do I go about retrieving it when needed for verification? Apologies for the rather longish question - please help.
psycopg2stores Unicode text, you must decode the salted password before inserting into the database:This prevents the
str()conversion being inserted instead (giving you"b'....'"in the database).Next, when querying
saltedpasswordis not a string, becausecursor.execute()does not return the results; it returnsNoneinstead.You'll need to fetch the result row:
Since rows contain Unicode text, you need to first encode to a bytestring before passing it to
bcrypt. You also want to use thebcrypt.checkpw()function to check the password:bcrypt.checkpw()avoids timing attacks when comparing strings, something your code is vulnerable to.