散列给出不同的结果

Hashing gives different result

我正在使用 Python 和 MySql 来处理用户身份验证。我已经使用完全相同的方法通过 python 添加了用户,但是当我尝试进行“登录”/身份验证时,它不匹配。

这是我的验证码:

# Collecting data from users. 
username=data['username']
password=data['password']

cur=mysql.connection.cursor()

# Checks if username exists. 
check_username = cur.execute("SELECT * FROM `users` WHERE `username`=%s",[username])

if check_username > 0:

     # Retrieves the correct salt of the user.
     cur.execute("SELECT `salt` FROM `users` WHERE `username`=%s",[username])
     get_salt = cur.fetchone()

     # Generates the hashed password of the user. 
     hashed_password=(hashlib.sha256((str(password[0:2])+str(get_salt[0])+str(password[2:])).encode('utf-8')).hexdigest()).lower()

     # Retrieves the hashed password of the user from the database. 
     cur.execute("SELECT `password` FROM `users` WHERE `username`=%s",[username])
     get_password = cur.fetchone()

     # Checks if identical.
     if get_password[0] == hashed_password:

          return jsonify("Authentication successful!"),201

     else: return jsonify("Authentication failed!"),401

else: return 'Incorrect username. Please try again.'

hashed_password 与数据库中存储的 return 散列密码不同。

这是我用来插入用户的代码。

username=data['username']
password=data['password']
salt=data['salt']

cur=mysql.connection.cursor()

# Generates the hashed password of the user. 
hashed_password=(hashlib.sha256((str(password[0:2])+str(salt[0])+str(password[2:])).encode('utf-8')).hexdigest()).lower() 

# Adds user to database.
add_user = cur.execute(" INSERT INTO `users` (`username`, `password`, `salt`) VALUES (%s, %s, %s);",[username,hashed_password, salt])

有人知道这是什么原因吗?

查看插入代码,您似乎将 salt 视为 get_salt 元组,获取第一项,不知道它原来是什么,这可能是您问题的根源,因为我不会期望你得到的第一个盐在一个元组中。

这是一个有效的版本,它使用的是 SQLite 而不是 MySQL,但除了格式化之外的变化很小。

此外,我建议您使用 hashlib.hash.update() 而不是您庞大而复杂的一步散列。默认情况下 hexdigest 是小写的,所以不需要 .lower() 它。

# db setup
import hashlib
import sqlite3

con = sqlite3.connect(":memory:")

cur = con.cursor()

cur.execute("CREATE TABLE users (username TEXT, salt TEXT, password TEXT)")

in_username = "ljmc"
in_salt = "verysecuresalt"
in_password = "p4assW0rD1!"

h = hashlib.sha256()
h.update(str(in_password[:2]).encode("utf-8"))
h.update(str(in_salt).encode("utf-8"))  # here salt[0] is just b"v" not the whole salt
h.update(str(in_password[2:]).encode("utf-8"))
in_hashed_password = h.hexdigest()

cur.execute(
    "INSERT INTO users VALUES (?, ?, ?)",
    (in_username, in_salt, in_hashed_password), # then store whole salt
)

con.commit()

# user check
username = in_username
password = good_password

# Checks if username exists.
check_username = cur.execute(
    "SELECT COUNT(*) FROM users WHERE username = ?", [username]
).fetchone()

if check_username[0] > 0:

    # Retrieves the correct salt of the user.
    cur.execute("SELECT salt FROM users WHERE username=?", [username])
    get_salt = cur.fetchone() # get the whole salt

    # Generates the hashed password of the user.
    hashed_password = (
        hashlib.sha256(
            (str(password[0:2]) + str(get_salt[0]) + str(password[2:])).encode(
                "utf-8"
            )
        ).hexdigest()
    ).lower() # use the whole salt

    # Retrieves the hashed password of the user from the database.
    cur.execute("SELECT password FROM users WHERE username=?", [username])
    get_password = cur.fetchone()

    # Checks if identical.
    if get_password[0] == hashed_password:
        print("Authentication successful!")
    else:
        print("Authentication failed!")

正如其他评论所指出的,在一个查询中获取所有用户数据然后应用逻辑也会好很多,因此检查块看起来像这样。

cur.execute(
    "SELECT username, salt, password FROM users WHERE username = ?",
    (username,),
)

if user := cur.fetchone():
    out_username, out_salt, out_password = user

    h = hashlib.sha256()
    h.update(str(password[:2]).encode("utf-8"))
    h.update(str(out_salt).encode("utf-8"))
    h.update(str(password[2:]).encode("utf-8"))
    print(f"is the password {password} ?", out_password == h.hexdigest())