8

After reading here a bit about salting passwords, it seems that it's best to use a unique salt for each user. I'm working on implementing Flask-Security atm, and from the documentation it appears you can only set a global salt: ie SECURITY_PASSWORD_SALT = 'thesalt'

Question: How would one go about making a unique salt for each password?

Thanks!

edit: from the docs on Flask-Security, I found this, which seems to again suggest that this module only uses a single salt for all passwords out of the box.

flask_security.utils.get_hmac(password)
    Returns a Base64 encoded HMAC+SHA512 of the password signed with the salt 
    specified by SECURITY_PASSWORD_SALT.
Chockomonkey
  • 3,895
  • 7
  • 38
  • 55
  • 1
    A global salt isn't a salt. If the same salt is used for everyone, then two users who happen to have the same password will have the same hashed password. That's the kind of thing a salt is intended to prevent. – Michael Burr Sep 19 '14 at 20:45
  • @MichaelBurr Okay, that's what i was thinking... which is why I'm confused. How do I use this setting to make a unique salt for each password? Or do I have to override the salting built-in to Flask-Security in order to do this? – Chockomonkey Sep 19 '14 at 21:30
  • 1
    I'm sorry - I know nothing about Flask. I was just commenting on the idea of a global salt. – Michael Burr Sep 19 '14 at 21:54

2 Answers2

16

Yes, Flask-Security does use per-user salts by design if using bcrypt (and other schemes such as des_crypt, pbkdf2_sha256, pbkdf2_sha512, sha256_crypt, sha512_crypt).

The config for 'SECURITY_PASSWORD_SALT' is only used for HMAC encryption. If you are using bcrypt as the hashing algorithm Flask-Security uses passlib for hashing and it generates a random salt during hashing. This confustion is noted in issue 268: https://github.com/mattupstate/flask-security/issues/268

It can be verified in the code, walking from encrypt to passlib:

flask_security/utils.py (lines 143-151, 39, and 269)

def encrypt_password(password):
   ...
   return _pwd_context.encrypt(signed)

_pwd_context = LocalProxy(lambda: _security.pwd_context)

flask_security/core.py (269, 244-251, and 18)

pwd_context=_get_pwd_context(app)

def _get_pwd_context(app):
    ...
    return CryptContext(schemes=schemes, default=pw_hash, deprecated=deprecated)

from passlib.context import CryptContext

and finally from: https://pythonhosted.org/passlib/password_hash_api.html#passlib.ifc.PasswordHash.encrypt

note that each call to encrypt() generates a new salt,

Artjom B.
  • 61,146
  • 24
  • 125
  • 222
trevor
  • 404
  • 5
  • 14
9

Turns out that if you use bcrypt, it takes care of the salting and stores it with the hash. So I'll go that route!

Thanks to this topic which lead me to this discovery:

Do I need to store the salt with bcrypt?

Community
  • 1
  • 1
Chockomonkey
  • 3,895
  • 7
  • 38
  • 55