You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

网站登录凭证加密问题:Fernet失效,求替代加密方案

问题分析与解决方案

核心错误:误解Fernet的使用逻辑

你遇到的问题并非Fernet加密机制本身的问题,而是用法错误:

  • Fernet每次加密同一明文时,会生成不同的密文(内置随机初始化向量IV),所以注册时把加密后的用户名存进数据库,登录时再加密输入的用户名去匹配,必然匹配失败——哪怕输入的用户名完全一致,两次加密结果也不同。
  • 你用str(encryptor.encrypt(...))将bytes类型密文转成字符串时,会自动带上b''包裹(比如密文b'xxx'会变成字符串"b'xxx'"),这也会导致存储和查询的字符串格式不一致,进一步加剧匹配失败问题。

更适合网站登录的方案

网站登录场景中,绝对不能用可逆加密存储密码(包括Fernet),一旦密钥泄露,所有用户密码都会被还原。正确做法是使用不可逆的密码哈希算法,常用的有:

  • bcrypt:安全性高,适配硬件迭代,优先推荐
  • Argon2:密码哈希竞赛冠军,安全性更强
  • PBKDF2:Python标准库自带,兼容性好

用户名无需加密,直接明文存储即可;若有隐私需求需加密存储,登录时需取出密文解密后和输入明文对比,而非加密输入去匹配。

修改后的代码示例(基于bcrypt)

先安装bcrypt:

pip install bcrypt

核心代码修改如下:

from flask import Flask, render_template, request,redirect
import sqlite3
import bcrypt

app = Flask(__name__)

@app.route('/', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        usernameInput = request.form['username']
        userpassInput = request.form['password']

        db_connect = sqlite3.connect("accounts.db")
        cur = db_connect.cursor()
        # 用明文用户名直接查询数据库
        cur.execute("""SELECT * FROM accountsDB WHERE userName=? or accessCode=?""", (usernameInput, usernameInput))
        userAccountName = cur.fetchone()
        
        if userAccountName:
            # 验证输入密码与数据库中存储的哈希是否匹配
            stored_hash = userAccountName[4]
            if bcrypt.checkpw(userpassInput.encode('utf-8'), stored_hash):
                return redirect('/userAccountPage', code=302)
            else:
                return 'Wrong Password'
        else:
            return 'No user Found'
    return render_template('login.html')

@app.route("/registration", methods=['GET', 'POST'])
def registrationPage():
    if request.method == 'POST':
        username_reg = request.form['username']
        userCode_reg = request.form['aime-access-code']
        userMaiName_reg = request.form['maimaiIGN']
        userpassword_reg = request.form['initialPassword']
        
        # 对密码生成哈希,仅存储哈希值
        pass_hash = bcrypt.hashpw(userpassword_reg.encode('utf-8'), bcrypt.gensalt())

        db_connect = sqlite3.connect("accounts.db")
        cur = db_connect.cursor()   
        # 用户名等信息明文存储,密码存储哈希值
        cur.execute("""INSERT INTO accountsDB(userName, accessCode, maimaiIGN, userPassword) VALUES (?,?,?,?)""",
                    (username_reg, userCode_reg, userMaiName_reg, pass_hash))
        
        db_connect.commit()
        return redirect('/', code=302)
    
    return render_template('registration.html')

额外注意事项

  • 数据库中userPassword字段需设置为足够长的类型(如TEXT),因为bcrypt生成的哈希字符串长度固定且较长。
  • 若需加密敏感信息(如accessCode),可继续使用Fernet,但查询时要取出密文解密后和输入明文对比;同时密钥需妥善保管,避免硬编码在代码中,建议通过环境变量加载。

内容的提问来源于stack exchange,提问作者Lord_Kordec

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 12:44:57