当前位置:  开发笔记 > 编程语言 > 正文

flask-bcrypt - ValueError:无效的盐

如何解决《flask-bcrypt-ValueError:无效的盐》经验,为你挑选了3个好方法。

我正在使用Flask和flask-Bcrypt完成一个简单的用户登录.但是,当尝试使用存储在我的数据库中的用户登录时,我不断收到此错误

ValueError: Invalid salt

models.py

class User(db.Model):

    __tablename__ = "users"

    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String, nullable=False)
    email = db.Column(db.String, nullable=False)
    password = db.Column(db.String, nullable=False)
    posts = db.relationship("Post", backref="author", lazy="dynamic")

    def __init__(self, name, email, password):
        self.name = name
        self.email = email
        self.password = bcrypt.generate_password_hash(password)

    def __repr__(self):
        return ''.format(self.name)

views.py

@app.route("/login", methods=["GET", "POST"])
def login():
    form = LoginForm()
    if form.validate_on_submit():
        user = User.query.filter(User.name == form.username.data).first()
        if user and bcrypt.check_password_hash(user.password, form.password.data):
            flash("you were just logged in!")
            login_user(user)
            return redirect(url_for("home"))
        else:
            flash("bad username or password")
    return render_template("login.html", form=form)

forms.py

class LoginForm(Form):
    username = StringField('username', validators=[DataRequired()])
    password = PasswordField('password', validators=[DataRequired()])

小智.. 12

我的问题类似于@tomClark所描述的

我用的Postgres作为我DDBB和他的司机,或DDBB系统,编码总是一个已编码的字符串.第二个编码过程创建一个无效的哈希,如下所示:

'\\x24326224313224483352757749766438764134333757365142464f4f4f464959664d66673575??467873754e466250716f3166375753696955556b2e36'

正确的哈希看起来像这样:

$2b$12$Wh/sgyuhro5ofqy2.5znc.35AjHwTTZzabz.uUOya8ChDpdwvROnm

要解决它,我首先将哈希解码utf8,而不是将其保存到DDBB.

示例代码:

def set_password(self, pw):
    pwhash = bcrypt.hashpw(pw.encode('utf8'), bcrypt.gensalt())
    self.password_hash = pwhash.decode('utf8') # decode the hash to prevent is encoded twice


Samuel Jaesc.. 9

如果在散列密码时出现任何问题,似乎也会返回此异常.

bcrypt来源hashpw():

hashed = _bcrypt.ffi.new("unsigned char[]", 128)
retval = _bcrypt.lib.crypt_rn(password, salt, hashed, len(hashed))

if not retval:
    raise ValueError("Invalid salt")

bcrypt(其中包Flask-Bcrypt用来完成工作)返回ValueError: Invalid salt时调用操作系统的bcrypt lib中返回一个错误.因此,如果由于某种原因它根本无法调用bcrypt lib,它仍将(错误地)返回Invalid salt错误.

似乎是bcrypt包实现中的一个缺陷- 它应该检查特定的值retval.


在我的情况下,错误结果与Apache mod_wsgi中的运行Flask有关virtualenv.我可以直接运行flask没有问题(使用flask-cli),但完全相同的应用程序实例bcrypt在运行时不会成功使用mod_wsgi.

通过修改我的Apache配置以使用virtualenv作为主要的Python环境来解决这个问题mod_wsgi.

httpd.conf/etc/httpd/conf.d/...添加:

WSGIPythonHome /path/to/my/application-virtualenv

有关此配置的更多信息,请参见此处:虚拟环境 - mod_wsgi文档

我仍然怀疑我的特定问题与我的系统的python站点包或其他与python包含相关的东西有关.


编辑:设置WSGIPythonHome结果不是解决问题.最后我用nginx切换到uWSGI.



1> 小智..:

我的问题类似于@tomClark所描述的

我用的Postgres作为我DDBB和他的司机,或DDBB系统,编码总是一个已编码的字符串.第二个编码过程创建一个无效的哈希,如下所示:

'\\x24326224313224483352757749766438764134333757365142464f4f4f464959664d66673575??467873754e466250716f3166375753696955556b2e36'

正确的哈希看起来像这样:

$2b$12$Wh/sgyuhro5ofqy2.5znc.35AjHwTTZzabz.uUOya8ChDpdwvROnm

要解决它,我首先将哈希解码utf8,而不是将其保存到DDBB.

示例代码:

def set_password(self, pw):
    pwhash = bcrypt.hashpw(pw.encode('utf8'), bcrypt.gensalt())
    self.password_hash = pwhash.decode('utf8') # decode the hash to prevent is encoded twice



2> Samuel Jaesc..:

如果在散列密码时出现任何问题,似乎也会返回此异常.

bcrypt来源hashpw():

hashed = _bcrypt.ffi.new("unsigned char[]", 128)
retval = _bcrypt.lib.crypt_rn(password, salt, hashed, len(hashed))

if not retval:
    raise ValueError("Invalid salt")

bcrypt(其中包Flask-Bcrypt用来完成工作)返回ValueError: Invalid salt时调用操作系统的bcrypt lib中返回一个错误.因此,如果由于某种原因它根本无法调用bcrypt lib,它仍将(错误地)返回Invalid salt错误.

似乎是bcrypt包实现中的一个缺陷- 它应该检查特定的值retval.


在我的情况下,错误结果与Apache mod_wsgi中的运行Flask有关virtualenv.我可以直接运行flask没有问题(使用flask-cli),但完全相同的应用程序实例bcrypt在运行时不会成功使用mod_wsgi.

通过修改我的Apache配置以使用virtualenv作为主要的Python环境来解决这个问题mod_wsgi.

httpd.conf/etc/httpd/conf.d/...添加:

WSGIPythonHome /path/to/my/application-virtualenv

有关此配置的更多信息,请参见此处:虚拟环境 - mod_wsgi文档

我仍然怀疑我的特定问题与我的系统的python站点包或其他与python包含相关的东西有关.


编辑:设置WSGIPythonHome结果不是解决问题.最后我用nginx切换到uWSGI.



3> thclark..:

就我而言,问题与密码存储期间进行的类型转换有关.使用bcrypt.generate_password_hash(plaintext)返回二进制值,如b'$2b$12$zf/TxXZ4JJZ/lFX/BWALaeo0M.wNXrQXLqIFjmZ0WebqfVo9NES56'.

与我的一样,您的密码列设置为字符串:

password = db.Column(db.String, nullable=False)

我发现上面生成哈希值,将二进制值存储在我的字符串密码列中,然后只是检索它导致了由于SQLAlchemy的类型转换而产生的不同值 - 与bcrypt完全无关!

关于正确列类型的问题帮助我意识到,为了正确的往返,我必须将密码存储为二进制.尝试使用以下代码替换列定义:

password = db.Column(db.Binary(60), nullable=False)

我不确定,但建议不同的生产环境和数据库可以不同地处理这种类型的转换(在某些情况下可逆转,而不是在其他情况下),或许可以解释@Samuel Jaeschke所带来的混合成功.

这也解释了为什么将输入字符串编码为约束字符集(较早的解决方案)在某些情况下可能有所帮助而不是其他情况 - 如果它导致从/到类型转换工作,那么您将从数据库中恢复正确的散列比较.

无论如何,这为我解决了这个问题.

推荐阅读
喜生-Da
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有