Performance and scalability: Password verification
I need some recommendations on best practice here, good people.
- Posted by: Johan Fredrik Varen
- Posted on: September 19 2005 07:50 EDT
I'm making a small web portal where users log in using an account name and a password. I wish to keep it so that even not the server administrator may gain access to this password. My own idea was to encrypt the password and store the cipher text in the database, using the same password as the encryption key. When the user logs in, the password provided is used to decrypt the cipher text, and if the decrypted text matches the password, then all is fine.
Then I spoke to my professor, who told me that common practice was to not store the password (even encrypted), but to run it through a hash function and store the resulting hash value. The guy is Chinese and no master in my own language, so I didn't quite get the whole idea. I understand, however, that this is how password verification is done on Unix.
So my question to you is whether I may safely use my own idea or follow the professor's advice. Should you suggest the latter, I would very much appreciate it if you could provide me with an idea of how to do this implementation wise in Java. Thank you.
I'd also recommend the hash version since it provides better security. A hash algorithm is by definition irreversible. The only method to break it is a brute force attack. You method is rather clever, but the encryption is reversible, so it might be easier to break it. Said that, even SHA is becoming more vulnerable nowadays, but it still is a good recommendation.
The only reason not to store the password's hash but the password (or it's encrypted version) is the need to provide a method for sending the user his password upon request in case he forgot it. But you wouldn't be able to achieve this with your method, neither, since you always need the correct password to decipher it. So better use the hash. "Forgot my password" functionality is better implemented by generating a new, temporary password, sending this to the user and making him change it after the first login, anyway.
Concerning the implementation, have a look at java.security.MessageDigest or jakarta's commons-digester library. Full blown authentication and authorization support could also quite easily be achieved by using the acegi security framework (http://acegisecurity.sourceforge.net/) in conjunction with the spring framework. This combination offers quite some extremely valuable functionality but would need you to get comfortable with the frameworks. Always worth a look, though, if you've got the time for evaluation.
I agree with useing hash method. But Thomas Jachmann said "You method is rather clever, but the encryption is reversible, so it might be easier to break it." is not correct.He use password as encryption key to encyrpt password,so the encrption is not reversible because it's key is not fixed as normal. I want to metion some points more:The encryption method is slower than hash method,and the latter will always be a fixed length string.
Here's a way to do it, that also takes 'Man-in-the-Middle' (MITM) attacks into consideration:
When a user enters a site, a session is created and the user gains a sessionid stored in a hidden form field.
The user enters his/hers user name and passphrase into the login form and click 'submit'.
Then, the passphrase is hashed client-side, and then this hash string is concatenated with the sessionid, like so (pseudo code):
key = hash( sessionid + hash(passwd) );
Finally, the 'key' is transfered over the web along with the user name, to the server.
The server stores passphrases in their hashed form: hash(passwd) in order to avoid revieling the passwords should it be compromised.
When the server retrives the form data from the login request, it looks up the user based on the user name and also fetches any additionaly needed data, such as the hashed passphrase.
Finally, since the server also knows the sessionid, it is now able to create it's own 'key' string as shown above. It then compares the two keys, and if they match, the user has properly identified itself.
While I do not say that this method makes MITM attacks impossible (it doesn't), it does, however, makes them more difficult - even more so, if coupled with some strong SSL (but if you have strong SSL, it can be discussed whether or not you need all this client-side hashing in the first place - but that requires a form of SSL that is tougher to break than spaghetti).
The key part is, that the passphrases aren't transmitted in clear text, and that they aren't stored in the database in clear text.
On which hash algorithms to use: MD5 and SHA-1 are beginning to show weak signs. The family of SHA-2 algorithms are probably the best choise for new systems.
Some people consider the time that the hashes are going to be stored in a system and compare it with speculations of when the MD5 and SHA-1 algorithms become dangurously weak.
But I think, that if the system is compromised just once and the hashes are recovered by the attacker, then all those considerations goes in the trash bin.
Another speculation that often come up, is how importaint the security of the system is; you might be tempted to think, that an account to a web portal is not particulary importaint - that's probably true, none the less, people often use the same password for many services: so the password you protect with your hashes are not just for your portal, but might also be for people e-mail, online banking and what not.
So, at least when it comes to passphrases, security should be rather tight.