问题描述
我正在为我的Web应用程序构建一个注册系统,其中用户提供用户名和密码。此数据存储在 postgresql
数据库中。我正在使用bcrypt生成用户输入密码的盐腌哈希,如下所示:
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())
一个看起来像这样的加盐密码- b'$ 2b $ 12 $ GskbcRCMFHGuXumrNt3FLO'
This creates a salted password that looks something like this - b'$2b$12$GskbcRCMFHGuXumrNt3FLO'
我正在存储此值在 postgresql
数据库中。接下来,当用户尝试登录系统时,我想验证其凭据。为此,我打算执行以下操作-
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")
这不起作用。它将引发以下 TypeError:必须先对Unicode对象进行编码,然后再进行散列
错误。
This does not work. It throws the following TypeError: Unicode-objects must be encoded before hashing
error.
我怀疑这个错误是因为变量 saltedpassword
将值存储为这样的字符串,例如 b'$ 2b $ 12 $ GskbcRCMFHGuXumrNt3FLO'
而不是普通的 b'$ 2b $ 12 $ GskbcRCMFHGuXumrNt3FLO'
(请注意引号盐腌的密码)
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.
推荐答案
psycopg2
存储Unicode 文本,您必须先解码加盐密码,然后再将其插入数据库:
psycopg2
stores Unicode text, you must decode the salted password before inserting into the database:
cur.execute("INSERT INTO test VALUES (%s, %s)",
(LoginIDFromWebForm, saltedpassword.decode('ascii')))
这样可以防止插入 str()
转换(这会给您 b'....'
This prevents the str()
conversion being inserted instead (giving you "b'....'"
in the database).
接下来,当查询 saltedpassword
不是字符串时,因为 cursor。 execute()
不返回结果;它会返回 None
。
Next, when querying saltedpassword
is not a string, because cursor.execute()
does not return the results; it returns None
instead.
您需要:
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')
由于行包含Unicode文本,因此您需要先将其编码为字节串,然后再将其传递给 bcrypt
。您还想使用 bcrypt.checkpw()
函数检查密码:
Since rows contain Unicode text, you need to first encode to a bytestring before passing it to bcrypt
. You also want to use the bcrypt.checkpw()
function to check the password:
if bcrypt.checkpw(PasswordFromWebForm.encode('UTF-8'), saltedpassword):
print("Success")
bcrypt.checkpw()
避免比较字符串时,您的代码容易受到攻击。
bcrypt.checkpw()
avoids timing attacks when comparing strings, something your code is vulnerable to.
这篇关于如何从数据库中检索密码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!