On Fri, Dec 23, 2016 at 9:19 PM, Frank Millman <fr...@chagford.com> wrote: > At present I just store a SHA-1 hash of the password for each user. Here are > my thoughts on improving this. > > 1. Generate a 'salt' for each password. There seem to be two ways in the > standard library to do this - > import os > salt = os.urandom(16) > > import secrets > salt = secrets.token_bytes(16) > > My guess is that it will not make much difference which I use.
The main difference is that the 'secrets' module is new in Python 3.6. If you use anything older - and there are a lot of 3.5s and 3.4s out there - you can't use it (unless there's a PyPI backport or something). So if you need compatibility with older Pythons, use os.urandom; if you're okay with 3.6+, use secrets. > 2. Store the salt in the database along with the user-id and hashed password > for each user. Yep. I generally work with a single database field containing the salt and the hash as a combined "encrypted password", as it's convenient to work that way. It's also often worth storing some kind of signature so you know what scheme you used; in the future, you will eventually decide that your passwords aren't really secure enough for long-term, and you'll want to progressively change over. You can't do that by decrypting and re-encrypting the passwords (since you can't decrypt them), so you have to introduce a new scheme while still supporting the old one. Technically you could detect the scheme by the encrypted length, but it's easier and safer to have a signature. > 3. Generate the password from the string supplied by the user as follows - > from hashlib import blake2b > password = blake2b('my_password'.encode('utf-8'), salt=salt).digest() > > The hashlib docs have the following warning - > > "Salted hashing (or just hashing) with BLAKE2 or any other general-purpose > cryptographic hash function, such as SHA-256, is not suitable for hashing > passwords. See BLAKE2 FAQ for more information." > > I propose to ignore this warning. I feel that, for my purposes, the above > procedure is adequate. > > Does all this sound reasonable? Check out some prior art. When I build a web app using Flask, I generally use Werkzeug's password management features: http://werkzeug.pocoo.org/docs/0.11/utils/#werkzeug.security.generate_password_hash http://werkzeug.pocoo.org/docs/0.11/utils/#werkzeug.security.check_password_hash As well as doing everything I said above about salting and hashing and having signatures, it pushes the responsibility onto someone else. You just give it a password and get back an ASCII string that you stash in the database. If there's a security flaw, Werkzeug can push a new version that fixes it - it's not your problem. At very least, be aware of what these kinds of libraries are doing. I'm not saying you should blindly trust them or automatically reach for a dependency, but they're worth looking at. ChrisA -- https://mail.python.org/mailman/listinfo/python-list