Threat Level: green Handler on Duty: Didier Stevens

SANS ISC: Store passwords the right way in your application - Internet Security | DShield SANS ISC InfoSec Forums


Sign Up for Free!   Forgot Password?
Log In or Sign Up for Free!
Store passwords the right way in your application
I suspect most of our readers know this, but it can't hurt to repeat this every so often as there is a lot of confusion on the issue. One thing that gets to me is seeing reports of website compromises that claim "the passwords were hashed with SHA-256". Well at face value that means 90% of the passwords were decoded before the news hit.
 
If you have an application that's protected by passwords, there are a few rules to follow:
 
Rule #1: Never store plain passwords, use a hash
 
The worst case solution is that passwords are stored as is. Any attacker breaking in to the application now has everything they need to impersonate any user in your application. But typically they have much more: your users typically reuse passwords, so there's no telling to how far this goes. And if the application is e.g. a webmail solution: well all accounts that can be reset by sending an email here are now essentially broken as well.
 
A hash function is a one-way function: it converts input to output but there is no easy way to reverse the process. There's a whole bunch of algorithms commonly used.
 
The goal/advantage here is that even if the attacker takes away the user tables, he's still got some work to do. 
Unfortunately the work is doable so we need more ...
 
Rule #2: Use a salt
 
Attackers can pre-compute (or buy) so called rainbow tables: it's a list of pre-computed password -> hash values and as such decoding any common password is as fast as a lookup to them gets.
 
A salt is essentially a random string chosen at the time of password change or creation and stored along with the hash and concatenated to the password. This makes rainbow tables useless.
 
But it's still not enough...
 
Rule #3: Use a slow hash function
 
This rule is most often forgotten, yet it is so critical. 
 
The most common hash functions we use daily (e.g. SHA-256) are designed to be fast. But for storing passwords that's going to work against us big time.
Even the attacker can't break SHA-512 in a brute force fashion, even if they can't use rainbow tables due to salts being used, they still will find the vast majority of the passwords our users can remember in a manner of minutes to hours if you use a fast hash.
 
So you need to use a slow hash function.
 
Since there's a Rule #0 in all things crypto: Don't invent your own: Just use the appropriate functions already there. Many of these slow hash functions allow one to chose the cost. If so, set it as high as you can bear with your current hardware.
 
Examples
 
In PHP one can use the crypt function using blowfish or many thousands of rounds of SHA-256 or SHA-512 instead of a simple hash function.
Or even better if the cryptographic password hashing extension is installed, use it as it has simple support for e.g. rehashing passwords to update the strength of a hash of a stored password upon login of the user.
 
Feel free to add comments on how to do it in other languages.

--
Swa Frantzen -- Section 66

Swa

760 Posts
I store them using notepad as passwords.txt on the desktop. No joke. It works.
Anonymous
Make sure you use ROT26 encryption at a minimum, Alibert.
Dean

135 Posts
There's a great write-up on this subject for PHP devs at:

http://www.openwall.com/articles/PHP-Users-Passwords

It includes code examples and links to a small framework that can be used to implement decent password handling without the (relatively-new) password hashing extension.

The article covers additional concerns beyond those listed here, such as timing attacks, input filtering and proper database access.
Dean
1 Posts
PBKDF2 is the only FIPS / NIST compliant "slow" hash to use. BCrypt and SCrypt, while nice, will not get you in compliance with a handful of regulations / certifications.
Dean
14 Posts
When thinking slow algorithm, make sure it is not slow enough that a hacker can use it for DoS on the server. Put in some logic to prevent they bad guys from doing brute force (.i.e. max 5 attemps per x minutes).
Povl H.

71 Posts
I don't really get the hype around salts.. You have to store the salt somewhere along the user data, or at least something from which the salt can be derived. If the attacker has gotten hold of your user database, he has the hash and the salt, and - in the worst case - even the stored DB procedure for the calculation. Even if he doesn't get the later part, trying out whether the hash fits for a concatenation of a plainly stored salt and password, or trying the usual other combinations (xor unhashed string with registration date etc..) just costs the attacker a few hours more.
Visi

41 Posts
@visi:

A salt really is no hype. without a salt the hacker can precompute all passwords he likes e.g. SHA-256("password") = 5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8 now with a table of all somewhat likely passwords the attacker has a simple sorted tree where he can look up the hash he found and retrieve the password without computing anything. We call that lookup table a rainbow table.
A salt prevents this attack as the passwords aren't hashed "naked".

The proper way is to generate a random salt per user and store it along the hashed password. In fact the output of the referenced PHP crypt function prepends the algorithm used (optionally the number of rounds used) and the salt to the hash it outputs, so you just store one string.

This way you force the attacker to compute hashes not just for your user table, but also for each and every individual user. A salt is hence all about forcing attackers to compute as many as possible hashes in order to retrieve your user's passwords.
Swa

760 Posts
The idea of 're-hashing' to change to a stronger hash on next login never occurred to me before, but sounds great.
Steven C.

171 Posts
I don't understand why more systems don't use a salted "slow" hash with the User ID as well and then include that User ID into the hashing of the password. This has the benefit that a stolen user database doesn't directly reveal User IDs which are often email addresses... which means they're likely to be long enough to be difficult to brute force quickly.
Anonymous
@visi the concept Swa is discussing is called "rainbow tables"
The wikipedia article has a good discussion.
Yes, it doesn't cover a slow a singular brute force, but it dramatically increases multiple account security.
Salting also prevents same password = same hash observations.
- I like the UserId hash idea!
dave

21 Posts
Per user salts _slow down_ a brute force attack. For example if I had "AAAA" as salt for user A and "BBBB" as salt for user B, then a password cracker would first need to append "AAAA" to a password and test for all possibilities, until a match was found, THEN they would have to do same thing for user B.

This method prevents "bulk" password cracking of every user in the database, because each user has their own salt. Even if you know that salt, this still slows down bulk attack. What this does not slow down is _targeted_ attacks, where only a few users are of interest to begin with.

This is where "slow" cryptographic hashes come into play. Where you "stretch" the hash to slow it down.
dave
14 Posts
"PBKDF2 is the only FIPS / NIST compliant "slow" hash to use. "
You mean the only NIST recommended hash. Bcrypt and Scrypt are not "non-compliant"; NIST just says absolutely nothing about them.

Bcrypt and Scrypt are resistant to attacks that PBKDF2 is not.

If you want to use PBKDF2; I think I would pad the password to 32 characters with all 1s; run Scrypt on the password first, then XOR its output with Bcrypt on the password

and store

PBKDF2(sha256(BCRYPT(password)) XOR sha256(SCRYPT(password)))

Basically, resulting in diversification against unknown weaknesses that could allow hardware-acceleration or quick computation of the hash algorithm, by implementing all 3.
Mysid

146 Posts
@Mysid NIST 800-132 shows all ciphers that make up PBKDF2 as being approved. Blowfish being absent from that list is a strike against BCrypt. No one said it was the best choice, but during your SDLC Phase 2, it is much easier to say "use PBKDF2 because auditors will be easier to deal with, then trying to explain away BCrypt".

http://security.stackexchange.com/questions/4781/do-any-security-experts-recommend-bcrypt-for-password-storage
Mysid
14 Posts
@hackajar, "use PBKDF2 because auditors will be easier to deal with, then trying to explain away BCrypt".

If you need to use PBKDF2, just because auditors will be easier to deal with, then perhaps auditors are not doing their job....

You have to make a decision at some point, if you want to
pick the less secure or attack-resistant solution, in order to appease auditors, or if you want to insist that auditors evaluate things appropriately, rather than pulling out some checklist, and claiming if it's not on the list, then it's insecure, and if it's on the list it must be secure.


Mysid

146 Posts

Sign Up for Free or Log In to start participating in the conversation!