From bb4745ed47fffc2da221fbed18ac6f318e8dd7bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krist=C3=B3f=20T=C3=B3th?= Date: Sat, 28 Apr 2018 16:13:35 +0200 Subject: [PATCH] Use best practices for password hashing in webservice --- solvable/Dockerfile | 3 ++- solvable/src/webservice/model.py | 11 +++++++++++ solvable/src/webservice/server.py | 16 +++++----------- 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/solvable/Dockerfile b/solvable/Dockerfile index aeca768..2a3472f 100644 --- a/solvable/Dockerfile +++ b/solvable/Dockerfile @@ -2,7 +2,8 @@ FROM eu.gcr.io/avatao-challengestore/tutorial-framework # Install webservice dependencies RUN pip3 install Flask==1.0 \ - SQLAlchemy==1.2.7 + SQLAlchemy==1.2.7 \ + passlib==1.7.1 # Define variables to use later ENV TFW_SERVER_DIR="/srv/.tfw" \ diff --git a/solvable/src/webservice/model.py b/solvable/src/webservice/model.py index cb34138..6f7f5ff 100644 --- a/solvable/src/webservice/model.py +++ b/solvable/src/webservice/model.py @@ -1,6 +1,7 @@ from sqlalchemy import Column, Integer, String, create_engine from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import scoped_session, sessionmaker +from passlib.hash import pbkdf2_sha256 engine = create_engine('sqlite:///db.db', convert_unicode=True) db_session = scoped_session(sessionmaker(autocommit=False, @@ -20,3 +21,13 @@ class User(Base): def init_db(): Base.metadata.create_all(bind=engine) + + +class PasswordHasher: + @staticmethod + def hash(password): + return pbkdf2_sha256.hash(password) + + @staticmethod + def verify(password, hash): + return pbkdf2_sha256.verify(password, hash) diff --git a/solvable/src/webservice/server.py b/solvable/src/webservice/server.py index 3e3a2a9..cc8795c 100644 --- a/solvable/src/webservice/server.py +++ b/solvable/src/webservice/server.py @@ -1,9 +1,8 @@ from os import urandom, getenv -from hashlib import sha512 from flask import Flask, render_template, request, session, url_for -from model import db_session, init_db, User +from model import db_session, init_db, User, PasswordHasher BASEURL = getenv('BASEURL', '') init_db() @@ -21,18 +20,12 @@ def remove_db_session(exception=None): db_session.remove() -def hash_password(password): - salt = 'justsomerandombytes'.encode() - return sha512(password.encode()+salt).hexdigest() - - @app.route('/', methods=['GET', 'POST']) def index(): if request.method == 'POST': - user = User.query.filter(User.username == request.form['username'], - User.passwordhash == hash_password(request.form['password'])).first() + user = User.query.filter(User.username == request.form['username']).first() - if not user: + if not user or not PasswordHasher.verify(request.form['password'], user.passwordhash): return render_template('login.html', alert='Invalid credentials!') else: session['logged_in'] = True @@ -53,10 +46,11 @@ def register(): return render_template('register.html', alert='Username already in use.') db_session().add(User(username=request.form['username'], - passwordhash=hash_password(request.form['password']))) + passwordhash=PasswordHasher.hash(request.form['password']))) db_session().commit() return render_template('login.html', success='Account "{}" successfully registered. You can log in now!'.format(request.form['username'])) + return render_template('register.html')