如何验证SQLite3数据库中Fernet加密的用户登录密码?
密码校验的正确解决方案
你遇到的问题根源是Fernet的设计特性:它每次加密同一明文时,会自动加入随机盐和时间戳,导致生成的密文唯一,所以直接对比两次加密结果的思路行不通。下面是两种可行的解决方法:
方法一:解密数据库存储的密文进行对比
登录时先根据用户输入的邮箱,从数据库中取出对应的加密密码,再用Fernet解密后和输入的明文密码比对,步骤如下:
修改后的代码:
import sqlite3 from cryptography.fernet import Fernet # 注意:实际项目中密钥不能硬编码,需通过环境变量等方式安全存储,且注册与登录必须使用同一密钥 key = b"你的实际密钥" fernet = Fernet(key) def loginFunc(): email = input("输入邮箱: ") password_input = input("输入密码: ") # 先根据邮箱查询对应的加密密码 cursor.execute('SELECT password FROM users WHERE email = ?', (email,)) result = cursor.fetchone() if result is None: print("邮箱不存在或密码错误") return stored_encrypted_pw = result[0] try: # 解密存储的密码并与输入明文对比 decrypted_pw = fernet.decrypt(stored_encrypted_pw).decode() print("登录成功" if decrypted_pw == password_input else "邮箱不存在或密码错误") except: # 解密失败(密钥错误、密文篡改等情况) print("验证失败")
方法二:改用密码哈希算法(更安全,行业推荐)
对称加密存储密码存在安全隐患:一旦密钥泄露,所有用户的明文密码都会被破解。行业标准做法是使用单向哈希算法(如bcrypt、Argon2、PBKDF2),这类算法会自动添加随机盐,且无法反向解密,只能通过专门的验证方法比对输入密码与存储的哈希值。
示例代码(使用bcrypt):
import sqlite3 import bcrypt def registerFunc(email, password): # 生成随机盐并哈希密码 salt = bcrypt.gensalt() hashed_pw = bcrypt.hashpw(password.encode(), salt) # 将邮箱和哈希后的密码存入数据库 cursor.execute('INSERT INTO users (email, password) VALUES (?, ?)', (email, hashed_pw)) conn.commit() def loginFunc(): email = input("输入邮箱: ") password_input = input("输入密码: ") cursor.execute('SELECT password FROM users WHERE email = ?', (email,)) result = cursor.fetchone() if result is None: print("邮箱不存在或密码错误") return stored_hashed_pw = result[0] # 验证输入密码与存储的哈希值是否匹配 print("登录成功" if bcrypt.checkpw(password_input.encode(), stored_hashed_pw) else "邮箱不存在或密码错误")
内容的提问来源于stack exchange,提问作者Ivan McKenna
相关产品推荐
相关产品推荐

