From a88b78af17c080b81fecce19f17611ca921632d3 Mon Sep 17 00:00:00 2001 From: Rogdham Date: Thu, 30 Aug 2012 16:40:02 +0200 Subject: [PATCH] Better crypto for storing passwords Instead of hash(passwd), store hash(SALT, key, passwd) where: - SALT is application-specific - key is random and changed each time passwd changes To login as admin the first time, go and see /login/1/victory --- main.py | 45 ++++++++++++++++++++++++++++++++------------- schema.sql | 5 +++-- 2 files changed, 35 insertions(+), 15 deletions(-) diff --git a/main.py b/main.py index c3ebd37..50a8452 100755 --- a/main.py +++ b/main.py @@ -15,11 +15,12 @@ import smtplib import string DATABASE = '/tmp/cavote.db' +PASSWD_SALT = 'change this value to some random chars!' SECRET_KEY = '{J@uRKO,xO-PK7B,jF?>iHbxLasF9s#zjOoy=+:' DEBUG = True TITLE = u"Cavote FFDN" EMAIL = '"' + TITLE + '"' + ' <' + u"cavote@ffdn.org" + '>' -VERSION = "cavote 0.1.0" +VERSION = "cavote 0.1.1" SMTP_SERVER = "10.33.33.30" PATTERNS = {u'Oui/Non': [u'Oui', u'Non'], u'Oui/Non/Blanc': [u'Oui', u'Non', u'Blanc'], u'Oui/Non/Peut-être': [u'Oui', u'Non', u'Peut-être']} @@ -57,8 +58,17 @@ def init_db(): #---------------- # Login / Logout -def valid_login(username, password): - return query_db('select * from users where email = ? and password = ?', [username, crypt(password)], one=True) +def valid_login(email, password): + # get user key + user_key = query_db('select key from users where email = ?', (email,), + one=True) + if not user_key: + # no such user + return None + user_key = user_key['key'] + # try password + return query_db('select * from users where email = ? and password = ?', + [email, crypt(password, user_key)], one=True) def connect_user(user): session['user'] = user @@ -68,8 +78,12 @@ def connect_user(user): def disconnect_user(): session.pop('user', None) -def crypt(passwd): - return hashlib.sha1(passwd).hexdigest() +def crypt(passwd, user_key): + # the per-user salt should not be stored in the db + # storing the passwd... but this is better than nothing + per_user_salt = hashlib.sha1(user_key).hexdigest() + salt_passwd = '%s%s%s' % (app.config['PASSWD_SALT'], per_user_salt, passwd) + return hashlib.sha1(salt_passwd).hexdigest() def keygen(): return hashlib.sha1(os.urandom(24)).hexdigest() @@ -116,7 +130,7 @@ def password_lost(): if user is None: flash('Cet utilisateur n\'existe pas !', 'error') else: - key = keygen() + key = 'v%s' % keygen() # start with v: valid key g.db.execute('update users set key = ? where id = ?', [key, user['id']]) g.db.commit() link = request.url_root + url_for('login_key', userid=user['id'], key=key) @@ -145,12 +159,10 @@ def password_lost(): @app.route('/login//') def login_key(userid, key): user = query_db('select * from users where id = ? and key = ?', [userid, key], one=True) - if user is None or user['key'] == "invalid": + if user is None or user['key'][0] != "v": abort(404) else: connect_user(user) - g.db.execute('update users set key = "invalid" where id = ?', [user['id']]) - g.db.commit() flash(u"Veuillez mettre à jour votre mot de passe", 'info') return redirect(url_for('user_password', userid=user['id'])) @@ -193,7 +205,12 @@ def user_password(userid): abort(401) if request.method == 'POST': if request.form['password'] == request.form['password2']: - g.db.execute('update users set password = ? where id = ?', [crypt(request.form['password']), session['user']['id']]) + # new (invalid) key + key = 'i%s' % keygen() # start with i: invalid key + print "\n\nchange key for %s\n" % key # FIXME TMP + g.db.execute('update users set password = ?, key = ? where id = ?', + [crypt(request.form['password'], key), + key, session['user']['id']]) g.db.commit() flash(u'Votre mot de passe a été mis à jour.', 'success') else: @@ -231,13 +248,15 @@ def admin_user_add(): if query_db('select * from users where email=?', [request.form['email']], one=True) is None: if request.form['username']: if query_db('select * from users where name=?', [request.form['username']], one=True) is None: - password = keygen() admin = 0 if 'admin' in request.form.keys(): admin = 1 - key = keygen() + key = 'v%s' % keygen() g.db.execute('insert into users (email, name, organization, password, is_admin, key) values (?, ?, ?, ?, ?, ?)', - [request.form['email'], request.form['username'], request.form['organization'], password, admin, key]) + [request.form['email'], + request.form['username'], + request.form['organization'], + '', admin, key]) g.db.commit() user = query_db('select * from users where email = ?', [request.form["email"]], one=True) if user: diff --git a/schema.sql b/schema.sql index 700c2a3..88a542b 100644 --- a/schema.sql +++ b/schema.sql @@ -83,9 +83,10 @@ create table user_choice ( -- Test data -INSERT INTO users (id, email, password, name, organization, is_admin, key) VALUES (1, "admin@admin.fr", "d033e22ae348aeb5660fc2140aec35850c4da997", "Toto (admin) Tata", "World corp", 1, "test"); -- mdp = admin +INSERT INTO users (id, email, password, name, organization, is_admin, key) +VALUES (1, "admin@admin.fr", "", "Toto (admin) Tata", "World corp", 1, "victory"); +-- to login, go to /login/1/victory INSERT INTO groups (id, name, system) VALUES (1, "Tous", 1); INSERT INTO groups (name) VALUES ("CA"); INSERT INTO groups (name) VALUES ("Membres"); INSERT INTO user_group (id_user, id_group) VALUES(1, 1); - -- 2.20.1