How to encrypt password using Python Flask-Security using bcrypt?
Rise to the top 3% as a developer or hire one of them at Toptal: https://topt.al/25cXVn
--------------------------------------------------
Music by Eric Matyas
https://www.soundimage.org
Track title: Ominous Technology Looping
--
Chapters
00:00 How To Encrypt Password Using Python Flask-Security Using Bcrypt?
01:18 Accepted Answer Score 11
02:04 Answer 2 Score 4
03:18 Answer 3 Score 0
03:48 Thank you
--
Full question
https://stackoverflow.com/questions/5219...
--
Content licensed under CC BY-SA
https://meta.stackexchange.com/help/lice...
--
Tags
#python #flask #flasksecurity
#avk47
ACCEPTED ANSWER
Score 11
Instead of storing the password you can use python's native decorators to store a hashed version of the password instead and make the password unreadable for security purposes, like this:
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(255), unique=True)
password_hash = db.Column(db.String(128))
@property
def password(self):
raise AttributeError('password not readable')
@password.setter
def password(self, password):
self.password_hash = bcrypt.hashpw('password', bcrypt.gensalt()))
# or whatever other hashing function you like.
You should add a verify password function inline with the bcrypt technolgy you implement:
def verify_password(self, password)
return some_check_hash_func(self.password_hash, password)
Then you can create a user with the usual:
User(email='a@example.com', password='abc')
and your Database should be populated with a hashed password_hash instead of a password attribute.
ANSWER 2
Score 4
You're right, create_user() doesn't hash the password. It is a lower-level method. If you are able to use registerable.register_user() instead, then it will hash the password for you. But if you would like to use create_user() directly, then just encrypt the password before calling it:
from flask import request
from flask_security.utils import encrypt_password
@bp.route('/register/', methods=['GET', 'POST'])
@anonymous_user_required
def register():
form = ExtendedRegistrationForm(request.form)
if form.validate_on_submit():
form_data = form.to_dict()
form_data['password'] = encrypt_password(form_data['password'])
user = security.datastore.create_user(**form_data)
security.datastore.commit()
# etc.
I wouldn't recommend overriding the password hashing on the User object, since Flask-Security uses the SECURITY_PASSWORD_HASH setting to store the password hashing algorithm. (It defaults to bcrypt, so you don't need to set this explicitly if you don't want to.) Flask-Security uses HMAC to salt the password, in addition to the SECURITY_PASSWORD_SALT which you provide, so just hashing the password using e.g. passlib with bcrypt won't result in a hash that Flask-Security will correctly match. You might be able to side-step this by cutting Flask-Security out of the loop and doing all password creation and comparison tasks yourself… but what's the point? You're using a security library, let it do security for you. They've already fixed the bugs you're bound to run into.
ANSWER 3
Score 0
Not sure if things have changed since this was asked, but the docs now state explicitly that
"Be aware that whatever password is passed in will be stored directly in the DB. Do NOT pass in a plaintext password! Best practice is to pass in hash_password(plaintext_password)." (emphasis mine)
i.e.:
from flask_security import hash_password
...
user_datastore = SQLAlchemyUserDatastore(db, User, Role)
app.security = Security(app, user_datastore)
...
app.security.datastore.create_user(email=email, password=hash_password(password), roles=roles)