flask-bcrypt-ValueError: недопустимая соль
Я заканчивала простого входа в систему пользователь с колбы и склянки-осуществляется. Однако при попытке войти с пользователем, который хранится в моей базе данных, я продолжаю получать эту ошибку
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 '<User {}>'.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()])
9 ответов:
В основном вы хотели бы закодировать свои данные перед хэшем: пароль.кодирование ('utf-8'). Если он приходит как unicode, это может вызвать ошибки. Взгляните также сюда: https://github.com/maxcountryman/flask-bcrypt/issues/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
.
В моем случае ошибка оказалась связанной с запуском Flask под Apache
mod_wsgi
вvirtualenv
. Я мог бы запустить flask напрямую без проблем (используяflask-cli
), но точно такой же экземпляр приложения не будет успешно использоватьbcrypt
при запуске подmod_wsgi
.Проблема была решена путем изменения конфигурации моего Apache для использования virtualenv в качестве основной среды Python для
mod_wsgi
.В
httpd.conf
или под/etc/httpd/conf.d/...
добавить:WSGIPythonHome /path/to/my/application-virtualenv
Дополнительную информацию об этой конфигурации можно найти здесь: Virtual Environments-mod_wsgi documentation
Я все еще подозреваю, что моя конкретная проблема связана с чем-то, что затеняется сайтпакетами python моей системы, или с чем-то еще, связанным с python includes.
Edit: установка
WSGIPythonHome
оказалась не для решения проблемы. В конце концов я переключился наuWSGI сnginx .
В моем случае проблема была связана с преобразованием типа, происходящим во время хранения пароля. Использование
bcrypt.generate_password_hash(plaintext)
возвращает двоичное значение, напримерb'$2b$12$zf/TxXZ4JJZ/lFX/BWALaeo0M.wNXrQXLqIFjmZ0WebqfVo9NES56'
.Как и у меня, ваш столбец пароля настроен в виде строки:
password = db.Column(db.String, nullable=False)
Я обнаружил, что генерация хэша выше, хранение этого двоичного значения в моем столбце string password, а затем просто получение его привело к другому значению из - за преобразования типа SQLAlchemy-ничего общего с bcrypt вообще!
Вопрос на тему: правильный тип столбца помог мне понять, что для правильного кругового перемещения я должен хранить пароли в двоичном виде. Попробуйте заменить определение столбца на:
password = db.Column(db.Binary(60), nullable=False)
Я не знаю наверняка, но предполагаю, что различные производственные среды и базы данных могут обрабатывать преобразование этого типа по-разному (обратимо в некоторых случаях, а не в других), возможно, объясняя смешанный успех @Samuel Jaeschke.
Это также объясняет, почему кодирование входной строки в ограниченный символ set (более раннее решение) может помочь в некоторых случаях, но не в других - если это приведет к преобразованию типа to/from, то вы восстановите правильный хэш из базы данных для сравнения.
Во всяком случае, это решило для меня эту проблему.
Моя проблема похожа на описанную @tomClark
Я использую Postgres как мой DDBB и его драйвер , или систему DDBB, кодирующую Всегда уже закодированную строку. Второй процесс кодирования создает недопустимый хэш следующим образом:'\\x24326224313224483352757749766438764134333757365142464f4f4f464959664d66673575467873754e466250716f3166375753696955556b2e36'
Правильный хэш выглядит так:
$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
Вам нужно применить
.decode('utf-8')
к вашемуself.password
:def set_password(self, password): """Set password.""" self.password = bcrypt.generate_password_hash(password).decode('utf-8')
Я верю, что вы используете Python 3 и bcrypt0.7.1. сначала вы должны удалить пользователей из вашей базы данных, а затем перейти к вашим моделям и добавить .декодируйте ('utf-8') в метод generate_password_hash () следующим образом:
pw_hash = bcrypt.generate_password_hash(‘hunter2’).decode('utf-8')
В качестве альтернативы вы можете удалить flask-bcrypt==0.7.1 и установить flask-bcrypt==0.62. Убедитесь, что вы удалить пользователей из таблицы перед установкой колбу-осуществляется==0.62
У меня была похожая проблема. Мой код для проверки пароля был следующим:
if check_password_hash(form.password.data, user.pw_hashed):
Когда я изменил порядок на:
if check_password_hash(user.pw_hashed, form.password.data):
Это сработало хорошо.
Вам совершенно не нужно
flask-bcrypt
для использованияbcrypt
.Просто сделайте что-нибудь вроде этого:
class User(Base): _password = db.Column("password", db.String, nullable=False) @hybrid_property def password(self): return self._password @password.setter def password(self, value): bvalue = bytes(value, 'utf-8') temp_hash = bcrypt.hashpw(bvalue, bcrypt.gensalt()) self._password = temp_hash.decode('utf-8') def check_password(self, value): return bcrypt.checkpw(value.encode('utf-8'), self._password.encode('utf-8'))
У меня была та же проблема. Оказалось, что имя пользователя и пароль, которые я пытался проверить, не были хэшированы в первую очередь. Убедитесь, что пароль для имени пользователя, которое вы пытаетесь проверить, уже хэширован, а не обычный текст. Если пароль сохранен в виде обычного текста без хэша, вы получите эту ошибку.