Looking to store usernames and passwords in a database, and am wondering what the safest way to do so is. I know I have to use a salt somewhere, but am not sure how to generate it securely or how to apply it to encrypt the password. Some sample Python code would be greatly appreciated. Thanks.
Store the password+salt as a hash and the salt. Take a look at how Django does it: basic docs and source.
In the db they store
<type of hash>$<salt>$<hash> in a single char field. You can also store the three parts in separate fields.
The function to set the password:
def set_password(self, raw_password): import random algo = 'sha1' salt = get_hexdigest(algo, str(random.random()), str(random.random()))[:5] hsh = get_hexdigest(algo, salt, raw_password) self.password = '%s$%s$%s' % (algo, salt, hsh)
The get_hexdigest is just a thin wrapper around some hashing algorithms. You can use hashlib for that. Something like
hashlib.sha1('%s%s' % (salt, hash)).hexdigest()
And the function to check the password:
def check_password(raw_password, enc_password): """ Returns a boolean of whether the raw_password was correct. Handles encryption formats behind the scenes. """ algo, salt, hsh = enc_password.split('$') return hsh == get_hexdigest(algo, salt, raw_password)
I think it is best to use a function dedicated to hashing passwords for this. I explain some reasons for this here: https://stackoverflow.com/a/10948614/893857
Nowadays the standard library has a dedicated section in the documentation for hashing password. It even mentions that you should get your salt from a cryptographically secure random source like
Here is a simpler way (taken from effbot), provided passwords with a length greater than 8 will not be a problem*:
import crypt import random, string def getsalt(chars = string.letters + string.digits): # generate a random 2-character 'salt' return random.choice(chars) + random.choice(chars)
for generate the password :
*: A password with a length greater than 8 is stripped from the right down to 8 chars long
I answered this here: https://stackoverflow.com/a/18488878/1661689, and so did @Koffie.
I don’t know how to emphasize enough that the accepted answer is NOT secure. It is better than plain text, and better than an unsalted hash, but it is still extremely vulnerable to dictionary and even brute-force attacks. Instead, please use a SLOW KDF like bcrypt (or at least PBKDF2 with 10,000 iterations)
For flask application or any python application you can use the werkzeug WSGI web application library, which provides you the option to generate and decode the password with salt and different types of algorithms in a format like this : method$salt$hash
The default salt length is 16 and algo used is sha256
from werkzeug.security import generate_password_hash, check_password_hash raw_pwd = 'mySecurePassword' # genreates the encrypted password hashed_pwd = generate_password_hash(raw_pwd) # to verify the password print(check_password_hash(hashed_pwd, raw_pwd)) # return boolean value after validating password
you can read more about werkzeug security here : https://werkzeug.palletsprojects.com/en/2.0.x/utils/#module-werkzeug.security