I am currently trying to use bcrypt to encrypt/hash my passwords from my seeds and store them in MYSQL but it keeps giving me the same password. I am using python. Any help would be appreciated!
User.py
from app.db import Base
from sqlalchemy.orm import validates
from sqlalchemy import Column, Integer, String
salt = bcrypt.gensalt()
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
username = Column(String(50), nullable=False)
email = Column(String(50), nullable=False, unique=True)
password = Column(String(200), nullable=False)
#validates('email')
def validate_email(self, key, email):
# make sure email address contains # character
assert '#' in email
return email
#validates('password')
def validate_password(self, key, password):
assert len(password) > 4
# encrypt password
return bcrypt.hashpw(password.encode('utf-8'), salt)
seeds.py
from app.models import User
from app.db import Session, Base, engine
# drop and rebuild tables
Base.metadata.drop_all(engine)
Base.metadata.create_all(engine)
db = Session()
# insert users
db.add_all([
User(username='alesmonde0', email='nwestnedge0#cbc.ca', password='password123'),
User(username='jwilloughway1', email='rmebes1#sogou.com', password='password123'),
User(username='iboddam2', email='cstoneman2#last.fm', password='password123'),
User(username='dstanmer3', email='ihellier3#goo.ne.jp', password='password123'),
User(username='djiri4', email='gmidgley4#weather.com', password='password123')
])
db.commit()
db.close()
Assuming that:
you have copied the code exactly as in your original file
and that the “keeps giving me the same password” means that in database the open text password gets saved and not the hash from validators
If both above is correct, the issue is with the identation, i.e. the “validate_password” method is not in the User class at all.
Try to ident it properly, it should trigger and hash the password.
it keeps giving me the same password
You pass the same password and salt every single time:
>>> salt = bcrypt.gensalt()
>>> bcrypt.hashpw('password123'.encode('utf-8'), salt)
b'$2b$12$L14/6UZsC4YymGUiQgBxCO5c6YoHEFDSM9ZSvBW0CgO9YkRUGkXwW'
>>> bcrypt.hashpw('password123'.encode('utf-8'), salt)
b'$2b$12$L14/6UZsC4YymGUiQgBxCO5c6YoHEFDSM9ZSvBW0CgO9YkRUGkXwW'
If you want the same plaintext to result in different hashes using bcrypt, regenerate the salt each time you generate a hash (as you should be per best practice):
>>> bcrypt.hashpw('password123'.encode('utf-8'), bcrypt.gensalt())
b'$2b$12$e1.vrDabeTDcqjqJ3Wj1fuapoGBgRaTjYNEn.v1WvuBbQLIsNlS3O'
>>> bcrypt.hashpw('password123'.encode('utf-8'), bcrypt.gensalt())
b'$2b$12$jqE4jMUeGfTLYixrR5iB0OAWSM/ZIEPiscX5fPLcxn8rOHqzJOUt6'
Related
The database looks like this:
class Users(UserMixin,db.Model):
__tablename__ = "users"
id = db.Column("id", db.Integer, primary_key=True)
username = db.Column(db.String(100))
hash_password = db.Column(db.Text)
secret_content = db.Column(db.Text)
The secret content is highly confidential, I don't even want the admin to know the content of the data.
My idea was to encode the content like this:
class Users(UserMixin,db.Model):
__tablename__ = "users"
id = db.Column("id", db.Integer, primary_key=True)
username = db.Column(db.String(100))
hash_password = db.Column(db.Text)
secret_content = db.Column(db.Text)
def __init__(self, username , password_hash, secret_content, key):
cipher_suite = Fernet(key)
self.username = username
self.secret_content = cipher_suite.encrypt(bytes(secret_content))
self.hash_password = password_hash
The key used to encrypt the data should be different for each user.
I wanted to create the key by hashing the password with sha256.
However, the hash is already stored in the user for login purposes.
Therefore I would use another hashing algorithm, MD5 for example.
The issue I see by doing that is that if a hacker is able to find/decypher this hash then he would be able to also extract the real password because at that point you can eliminate a lot of possibilities when the hacker brute forces the password.
Do I have other options or will I need to ask the user for a second unrelated password?
Based on the comments from #Artjom B.
Add salt to the key.
Encrypt key with PBKDF2 to encode the personal data with.
Encrypt the same key with sh256 for user login.
I am following the tutorial at https://www.digitalocean.com/community/tutorials/how-to-add-authentication-to-your-app-with-flask-login for adding register/login features to a flask app, which uses Flask-Login with an SQLite database (using flask_sqlalchemy). As such, it has code like the following for initializing the SQLite database (from init.py):
db = SQLAlchemy()
def create_app():
app = Flask(__name__)
app.config['SECRET_KEY'] = '9OLWxND4o83j4K4iuopO'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///db.sqlite'
db.init_app(app)
And then creates a User class (as is required by Flask-Login) like this:
from flask_login import UserMixin
from . import db
class User(UserMixin, db.Model):
id = db.Column(db.Integer, primary_key=True) # primary keys are required by SQLAlchemy
email = db.Column(db.String(100), unique=True)
password = db.Column(db.String(100))
name = db.Column(db.String(1000))
However, I want to store user information in a dynamodb table, not a SQLite table. How then should I write the User class? I want each User to have an email, password and name property like in this tutorial (along with other properties/methods required at https://flask-login.readthedocs.io/en/latest/#your-user-class as is handled by UserMixin), but am unsure how to write the class when using dynamodb.
I wrote the User class simply as follows:
class User(UserMixin):
def __init__(self, id, email, name, password):
self.id = id
self.email = email
self.name = name
self.password = password
I used the User class from ZhouW and you will also need a custom user_loader. This here should work:
class User(UserMixin):
def __init__(self, id, email, password):
self.id = id
self.email = email
self.password = password
#login_manager.user_loader
def loader(user_id):
response = table.query(
KeyConditionExpression=Key('id').eq(user_id))
if response["Count"] == 0:
return
user = User(id=response['Items'][0]["id"], email=response['Items'][0]["email"], password=response['Items'][0]["password"])
return user
Will need a table first, connect something like this:
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('users')
from boto3.dynamodb.conditions import Key
I want to load database value? using sql alchmey.
If I ask using get mehtod '127.0.0.1/api/v1/user/25/'
There is a value in database(id=5, username=jaeyeon, email=jae#naver.com)
I want to show this column.
but it can't. Where can I fix the code?
I don't know how parameter deliver.. Please help me :(
from flask import Flask, url_for, redirect
from flask_sqlalchemy import SQLAlchemy
from flask_restful import reqparse, abort, Api, Resource
app = Flask(__name__)
api = Api(app)
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:12345#localhost/catchat'
db = SQLAlchemy(app)
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True)
email = db.Column(db.String(120), unique=True)
password = db.Column(db.String(120), unique=True)
def __init__(self, username, email, password):
self.username = username
self.email = email
self.password = password
def __repr__(self):
return '<User %r>' % self.username
class user(Resource):
def get(self, id):
args = parser.parse_args()
user_id = db.session.query(User.id == args['id']).filter(id)
print user_id
entry = [dict(id=user.id, username=user.username, email=user.email, password=user.password)]
print entry
return entry, 200
api.add_resource(user,'/api/v1/user/<int:id>')
if __name__ == '__main__':
app.run(debug=True)
You've set up your session a bit differently than I'm used to doing, so I'm not sure whether that makes any difference, but I can see some issues with the query you're making. Try this instead:
user_id = db.session.query(User).filter_by(id = args['id']).one()
Assuming that args['id'] is going to produce the proper value, then this will return the single matching row from User, and you can use dot notation to access the columns. I see you seem to be a bit off when using the dot notation, remember that the values are now stored in user_id so you'd have to access them like this:
email = user_id.email
I am working on a flask app based on http://code.tutsplus.com/tutorials/intro-to-flask-signing-in-and-out--net-29982.
As part of the tut I'm trying to connect to a postgres server, with a structure as in the screenshot. I've added a db 'flask' which you can see.
Based on the tut I have the following code in my main file ('routes.py'):
from flask.ext.sqlalchemy import SQLAlchemy
from flask import Flask
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = "postgresql://postgres:123#localhost/flask"
db = SQLAlchemy(app)
from models import User
# db.init_app(app)
db.create_all()
db.session.commit()
admin = User('admin', 'admin#example.com', 'admin1', 'admin1#example.com')
guest = User('admi2', 'admin#ex1ample.com', 'admin', 'admin2#example.com')
# guest = User('guest', 'guest#example.com')
db.session.add(admin)
db.session.add(guest)
db.session.commit()
models.py:
from flask.ext.sqlalchemy import SQLAlchemy
from werkzeug import generate_password_hash, check_password_hash
db = SQLAlchemy()
class User(db.Model):
__tablename__ = 'users'
uid = db.Column(db.Integer, primary_key = True)
firstname = db.Column(db.String(100))
lastname = db.Column(db.String(100))
email = db.Column(db.String(120), unique=True)
pwdhash = db.Column(db.String(54))
def __init__(self, firstname, lastname, email, password):
self.firstname = firstname.title()
self.lastname = lastname.title()
self.email = email.lower()
self.set_password(password)
def set_password(self, password):
self.pwdhash = generate_password_hash(password)
def check_password(self, password):
return check_password_hash(self.pwdhash, password)
When run the debugger gives:
sqlalchemy.exc.ProgrammingError: (psycopg2.ProgrammingError) relation "users" does not exist
LINE 1: INSERT INTO users (firstname, lastname, email, pwdhash) VALU...
^
[SQL: 'INSERT INTO users (firstname, lastname, email, pwdhash) VALUES (%(firstname)s, %(lastname)s, %(email)s, %(pwdhash)s) RETURNING users.uid'] [parameters: {'lastname': 'Admin#Example.Com', 'firstname': 'Admin', 'pwdhash': 'pbkdf2:sha1:1000$eZvJNKHO$64f59c34364e3d6094d126fa3ca2b327ab39e302', 'email': 'admin1'}]
What am I doing wrong?
You're initializing your database twice.
I'd suggest taking a good look at this: http://flask.pocoo.org/docs/0.10/patterns/sqlalchemy/
Essentially, you'll want to split things up into a few more files to prevent import issues and make things a little more clean. I've done the below which seems to work. Note, I've used SQLite, since I do not have Postgres installed on this box.
app.py
from flask import Flask
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////test11.db'
models.py
from flask.ext.sqlalchemy import SQLAlchemy
from app import app
db = SQLAlchemy(app)
class User(db.Model):
__tablename__ = 'users'
uid = db.Column(db.Integer, primary_key = True)
firstname = db.Column(db.String(100))
lastname = db.Column(db.String(100))
email = db.Column(db.String(120), unique=True)
pwdhash = db.Column(db.String(54))
def __init__(self, firstname, lastname, email, password):
self.firstname = firstname.title()
self.lastname = lastname.title()
self.email = email.lower()
self.set_password(password)
def set_password(self, password):
self.pwdhash = (password)
def check_password(self, password):
return password
routes.py
from models import User, db
db.create_all()
db.session.commit()
admin = User('admin', 'admin#example.com', 'admin1', 'admin1#example.com')
guest = User('admi2', 'admin#ex1ample.com', 'admin', 'admin2#example.com')
db.session.add(admin)
db.session.add(guest)
db.session.commit()
I'd definitely suggest looking over some tutorials! You'll need it: you should learn about web vulnerabilities, best practices, and so on.
The tutorial you linked to has a section called "Create a User Model", under which it tells you how to use CREATE TABLE ... to create your users table. It gives some MySQL-specific syntax for this, although you are apparently using Postgres, so your command will be slightly different.
But the screenshot you posted (from pgAdmin?) clearly shows that the "public" schema in the flask database has zero tables, so obviously you have not created this table yet. You'll have to create this table, you should be able to do so through pgAdmin, something like:
CREATE TABLE users (
uid serial PRIMARY KEY,
firstname varchar(100) not null,
... follow the guide for the rest of the columns ...
);
Being a newb to python I am not quite sure why I am getting inconsistent results.
I register a user and the password in my table ends up being the hashed version. When the user updates his password, the password in the table ends up being the unhashed version. Obviously, I want the hashed version. What am I doing wrong? (I am using SQLAlchemy and mysql if that matters.)
I have the following:
def hash_password(password):
blah, blah, blah # hash my password here
return hashed_password
class User(Base):
__tablename__ = 'mytable'
email = Column('email')
_password = Column('password')
def _get_password(self):
return self._password
def _set_password(self, password):
self._password = hash_password(password)
password = property(_get_password, _set_password)
password = synonym('_password', descriptor=password)
def __init__(self, password="", email=""):
self.email = email
self.password = password
#classmethod
def register(cls, email, password):
return DBSession.add(User(email=email,password=password)) # this correctly hashes the password
#classmethod
def update(cls, email, password):
return DBSession.query(cls).filter(cls.email == email).update({'password': password}) #password ends up being the unhashed password
The issue here is the way that you are updating the password via your User.update method. This method is skipping the ORM entirely and updating the row directly in the database. It should be obvious that the code to hash the password will not run when you do this. The User model that you pasted is just fine and similar to what I use. You need to use it though. This means that to update a password you should load the user, and set their password.
user = DBSession.query(User).filter_by(email=email).first()
if user:
user.password = new_password
and later when the transaction is committed things will be the way you expect.
You should store password hash in database, so field of your model must contain hash value, not raw password. To set password, you should use methods, that makes hashing and set hash to instance. To check, if password is correct, you should hash user-defined password and compare result with hash stored in your instance. Yo will not be able to decode password from hash - it's unsecure.
class User(Base):
__tablename__ = 'user'
email = Column('email', String(80))
password = Column('password', String(80))
def set_password(raw_password):
self.password = hash(raw_password)
def check_password(raw_password):
return self.password == hash(raw_password)