Ask Slashdot: Definitive Password Management Best Practices Using OSS?
jmcbain writes: I am an software engineer for a client-server user account system handling both Web and smartphone clients. I have been searching for definitive and crystal-clear best practices for managing user account and password data using open-source software, but I have only cobbled together a complete picture from dozens of websites. I currently have a system that sends passwords over SSL and performs bcrypt hashing for storage and authentication checking at the server side. Is that good enough? The recent Ashley Madison breach and the exposure of MD5-hashed passwords (as opposed to bcrypt) has me worried again. Can someone please suggest a definitive, cookbook-style Web resource or book on how to use open-source software to handle user passwords for multiple client-server scenarios? I would like answers to questions such as: Where do I perform hashing (smartphone/web client or server)? What hash algorithm should I use? How do I store the hashes? How can clients recover forgotten passwords? etc.
Owasp authentication cheat sheet:
https://www.owasp.org/index.php/Authentication_Cheat_Sheet
Use Kerberos with one of the heftier encryption types. Don't use the default Crypt Password type used in Shadow Passwords, and store your accounts in OpenLDAP, not a SQL Database
Where do I perform hashing (smartphone/web client or server)?
You hash twice, with different salts - once on the client side and once again (i.e., hash the hash) on the server side. The doubly-salted, doubly-hashed password is the one you store.
What hash algorithm should I use?
You said it yourself - bcrypt. bcrypt allows you to set a cost, which increases password brute-forcing difficulty but also increases computational cost on every verification. Set the cost to be the maximum you can handle - if you have a stronger computer and fewer users, you can set a higher cost.
How do I store the hashes?
Chrome uses encrypted SQLite for browser saved passwords. Which encryption depends on the platform - Windows has CryptProtectData, KDE and Gnome have keyrings. The basic idea for all of these is to use some symmetric encryption algorithm (e.g. AES) with the key derived from some set of hashes on machine-specific data, like hardware serial numbers. If you want to go hardcore, use a hardware encryption dongle (HSM).
Note that it is important to encrypt the file on disk, but it is also important to make sure that decrypted hashes stay in server memory for as little as possible.
How can clients recover forgotten passwords?
They can't recover forgotten passwords - you're only storing hashes, remember? What they can do is reset their password. Two factor authentication is best (a verified email account and phone number, if you can send SMSes or automated calls), but at least email and a security question seems to be the standard.
If you use a one way hash that has been properly salted (i.e., HASH(SALT + password) ), then you should never be able to retrieve forgotten passwords, ever. If you can retrieve a lost password for a user, then you've screwed it up, because if you can recover a lost password, someone who scraped your database can recover a lost password.
The worst, by the way, are web sites which require you to pick a super-secure password (at least 12 characters long, must contain punctuation, both upper and lower case letters, a number character, an Egyptian hieroglyph, and must not match the last 15 passwords used in the past and must be changed ever 30 days)--then stores the password and password history as plain text in the user database. Those are the guys I'd love to murder in cold blood.
Personally I've always liked using some element of a user record attribute as part of the SALT--such as having a UUID associated with each user record that becomes part of the salt for the hash (i.e., HASH(SALT + password + UUID) )--because this means if someone does scrape your database it's computationally a little more difficult to reverse engineer the passwords in the database because even a bunch of people use "123456" as their password, the hashes will be different for each of those users. Of course the UUID must never change or else you'll lock your users out.
I'm also a fan of the POP3 protocol's APOP authentication mechanism, where sending credentials over the 'net requires two transactions: (1) obtaining a unique token for that session, then (2) hashing the password against that token to transmit to the back end. Of course this means you wind up hashing the plain text password *twice*: since you don't have the password on the back end (but its hash) you can only compare against HASH(TOKEN + hashed_password), and on the front end you wind up calculating HASH(TOKEN + HASH(SALT + password + UUID) ). But that requires a lot of work in the client.
Simply sending HASH(SALT + password + UUID) rather than hashing the hash with an additional token means you're subject to a replay attack, where a third party could listen in on the conversation and simply replay the login packet you send to connect to the server.
And while I know a lot of folks claim that all of this is mitigated by using SSH, it doesn't protect against man-in-the-middle attacks, including incidental man-in-the-middle attacks created by certain proxy gateways which use their own certs in order to decrypt HTTP traffic to sniff for viruses or enforce corporate guidelines for acceptable use.
Ultimately security won't stop the most determined hackers; you're not stopping the NSA, for example. But you can stop the script kiddies and disgruntled employees by taking some precautions--such as never storing sensitive information in a database (like credit cards) unencrypted, and using one-way hashes to store passwords.
Oh, and as a footnote: unless you have a Ph.D. in cryptography, don't write your own random functions or hash functions. Yes, I've seen it in the field. Instead, use a cryptographically secure hash function. Heck, even MD-5 is going to be better than anything you try to roll on your own.
I'm tooting my own horn, but you might find my article on long-term password hashing strategies helpful:
https://medium.com/@uther_bendragon/sustainable-password-hashing-8c6bd5de3844
TL;DR version:
1) Use a one-way collision-resistant algorithm developed by professional cryptographers, and the implementation of which has been adequately studied and understood;
2) Do not use an algorithm with known vulnerabilities (this obvious step is sometimes not followed);
3) Use randomly-generated data—salt as additional input to the algorithm to minimize vulnerability to rainbow/lookup table attacks. The salt should be generated from a Cryptographically Secure Pseudo-Random Number Generator;
4) Use a long salt, preferably as long as the output of the hash function;
5) Use an adaptive hashing algorithm—that is to say, an algorithm with a configurable number of encryption iterations to slow attackers (a.k.a. key stretching). The number of iterations can be tuned as the speed of available hardware increases to keep the resulting hash secure. Such choices include PBKDF2, bcrypt and now scrypt.
6) At at some point you will need to change your hashing function, in fact, probably many times. So store the algorithm along with the hash e.g. ALG:HASH:SALT
7) secure legacy hashes by wrapping the obsolete hash with a new one e.g. encrypt the md5 hash of the guy who hasn't logged in for years in your new hashing algorithm and store it with a token like md5|pbkdf2:hash:salt