Why is proper password hashing essential in protecting your users? And what is proper hashing, anyway?
I was talking at the Passwords13 Las Vegas, USA, a conference focused only on passwords & PIN codes, about various ways of storing users' passwords in a database. I was the first web developer ever to speak at this conference.
I also presented one real world example by using a dumped dataset with several hundred hashed passwords from a small local (Czech) online shop for a major clothing brand. I demonstrated that it's possible to take over user's mailbox (including a gmail.com mailbox with additional protection) by cracking passwords from this dataset simply by using an online cracking tool. That is few dozens of active mailboxes in several minutes with just a browser. I presented some stats gathered while working with this dataset – how many passwords were successfully cracked by this online tool and how many were additionally cracked using a tool called hashcat on a regular laptop. I recommended better hashing algos than just a plain SHA-1, like scrypt and bcrypt. As a bonus I added few tips like don't send passwords by email.
http://www.michalspacek.cz/prednasky/hash-store-profit-passwords
http://www.youtube.com/watch?v=5RX-qUQ0iN4
1. Michal Špaček, Passwords13, Las Vegas
www.michalspacek.cz @spazef0rze
1.1. HashHash
2.2. StoreStore
3.3. ……
4.4. Profit!Profit!
2. Why is proper password hashing essential in protecting your users? And what is proper
hashing, anyway? Every year we see a major web site exposing user accounts including e-mails
and passwords due to various security issues. Besides these big names there's a lot of smaller
leaks which nobody really cares about. Except the guys looking for accounts to have fun with.
Leaking users login credentials has fatal consequences and I'll show you why and how
to avoid it. Let's have a look at a website of a local though expanding Czech outdoor wear brand.
3. Michal Špaček @spazef0rze
One of the websites this company runs once had a robots.txt file which looked exactly like this.
The tmp directory had listing enabled so humans (not robots) could download the files including
a backup of the user database. No SQL injection attack needed, it's passwords on a silver platter.
4. Michal Špaček @spazef0rze
323 usernames & emails
+
passwords (SHA-1, no salt)
The total amount of user accounts was quite low, nothing to compare to the 32 million
passwords from the infamous RockYou leak from 2009. Unlike the RockYou passwords which
were stored in readable plaintext form, these passwords were hashed using SHA-1 but not salted.
5. Michal Špaček @spazef0rze
323 usernames & emails
+
passwords (SHA-1, no salt)
crackstation.net
Instead of cracking the passwords myself I took a different approach. Is it possible to crack the
passwords using just a browser and some third-party service so that anyone with access to
the leaked data and virtually no knowledge of how to crack passwords can actually crack them?
6. Michal Špaček @spazef0rze
crackstation.net
111 cracked passwords
Using one such online service I was able to recover 111 passwords from the whole data set in
few minutes thanks to massive pre-computed lookup tables the site uses. The site employs
CAPTCHA which renders the site unusable for cracking larger data sets, but that wasn't the case.
7. Michal Špaček @spazef0rze
exoddus
Tbvfs1
9plams
P1ll3d
Neznašov
These are some of the passwords the CrackStation site was able to find in its huge dictionary of
words and other strings. The last one is a name of a Czech village and the P1ll3d password meets
password criteria for most of the web sites: has at least 6 characters, one capital and some digits.
8. Michal Špaček @spazef0rze
111 cracked passwords
52 accounts with
…@seznam.cz
Out of that 111 cracked passwords 52 belonged to accounts having an e-mail address hosted at
seznam.cz. Seznam is a major local search engine in the Czech Republic and also provides e-mail
services. Actually, Czech Republic is one of the few countries where local player beats Google.
9. Michal Špaček @spazef0rze
52 accounts with …@seznam.cz
How many passwords to the
…@seznam.cz mailbox itself?
In total there were 165 accounts with e-mail hosted at seznam.cz and I wanted to find out how
many of those 52 cracked passwords were used also to access the mailboxes. Worth noting is
that after finding the data I've notified the owner of the site and recommended them to tell their
users to change their passwords and that I first ran this test 6 months after the data leaked. I've
re-run the same test 10 months after the leak only to find out that not a single user actually have
changed their password. Whether they were really told to do so is something I don't know.
10. Out of 52 passwords I've recovered using the CrackStation service, 9 of them were also used
to access the mailbox hosted at seznam.cz. That's 9 users re-using their e-mail password
elsewhere and especially to sign in to this e-shop. Gaining access to the mailbox is fatal
because it contains messages from other sites sending login credentials after signing up (which
nobody changes afterwards) and also because most sites send password reset links via e-mail
or even send the password itself so hijacking or getting access to other services is quite possible.
11. Michal Špaček @spazef0rze
…@email.cz 2 out of 9
…@centrum.cz 3 out of 9
…@gmail.com 1 out of 15
And with access to 9 seznam.cz mailboxes it does not stop. Out of 9 email.cz users just a few
were re-using the password. Accessing the Gmail account was bit challenging as Google has
correctly detected that by using Tor anonymising tool I've come from an unusual location.
12. So Gmail asked for some confirmation that it's really me trying to sign in and wanted me to
provide a phone number of that particular user. Well, who else than me would be me, so I said
"Google, maybe you already know" and googled that number right away. Nice try, Google.
13. Michal Špaček @spazef0rze
hashcat
164 more cracked passwords
I've run the rest of the passwords through the hashcat password cracker and I got 164 more
cracked passwords leaving 48 of them uncracked. The tool was running for a week or so before
I've interrupted it. My cracking rig was a regular laptop so hashcat used only the CPU with AVX.
14. Michal Špaček @spazef0rze
164 more cracked passwords
2 also used for mailbox
Interesting fact is that out of these hashcat-cracked passwords, only 2 of them were used also
for mailbox access. Seems that majority of people and mainly mailboxes in this case used
passwords which are already known and added to a dictionary used by the CrackStation service.
15. Email Password!
The reason why people are re-using their e-mail password at other web sites might be the web
applications themselves. Look at the sign-up fields above. Users will enter their e-mail password
just because the form says so. It'd better have a note saying "Don't use your email password".
16. Storing user passwords in your database in a wrong way will put your users in real danger. The
attacker can gain access to multiple web sites by attacking just one unsafe password storage. My
wild guess is that 50% of you are storing the passwords in a bad way. No, not you. The other you.
17. Michal Špaček @spazef0rze
in readable form
(in plaintext form)
But what does it mean, to store passwords in a wrong way? The simplest form of unsafe
password storage is plaintext storage. That is to store the password just like it arrived from the
browser. No hashing, that's a rude word. "The application is fully secured". Yeah, no worries.
18. If you store passwords just like that then this friendly guy will drop by your web application one
day. Just don't do it, don't store passwords just like that, in readable plaintext form.
If somebody will somehow access your database or find backups, your users' data are in danger.
19. Michal Špaček @spazef0rze
MD5(password)
SHA-1(password)
CRC32(password)
By now you've definitely heard about password hashing – running a password through a hashing
function before storing it to a database. That's the right thing to do although not entirely. There
are better and worse password hashing functions. And even the better ones can be used wrongly.
20. So MD5, SHA-1 and CRC32 are not the password hashing functions you are looking for, especially
when used as shown before. You've seen a case in the beginning where passwords were hashed
using SHA-1 but it wasn't enough to keep them safe and passwords were easily cracked. So it's no.
21. And it's no not just because MD5 and SHA-1 can be quickly cracked but also because there are
online pre-computed lookup tables of different MD5 and SHA-1 hashes mapped to their original
strings. If your hashes are not salted, a lot of passwords can be recovered by just googling them.
22. If these pre-computed lookup tables are not enough to recover the password then maybe a special
password cracker utilizing a GPU or two will help. In 2012, Jeremi Gosney built a cluster with 25
GPUs capable of trying 180 billion combinations/sec against the MD5 hash. Yes, that's a computer.
23. This year Jeremi got his Christmas presents early. Looking at the massive computing power he's
got there on the table almost ready to crack your passwords one by one we can only assume that
storing MD5 or SHA-1 hashed passwords equals to storing them in plaintext. Don't. Do. That.
25. The function call loop should be executed at least several thousand times. It also much depends
on the algorithm used. If you use MD5 for multiple hashing the total count of collisions found by
method called tunnelling gets higher. And I hate tunnels. You know, they're too underground.
26. From all the things presented so far it's obvious that we need a slow hashing function. Well,
kinda slow. The time required for hashing a password should be long enough to make brute-force
attack take forever but short enough so that the server can respond to other requests as well.
27. Michal Špaček @spazef0rze
MD5(password + salt)
SHA-1(password + salt)
If you've heard about password hashing, you've definitely heard about a salt too. Using salt
when hashing passwords is essential. Random and unique salt can be stored in readable form in
the database and the main purpose of salting is to prevent the attacker to use pre-computed hash
lookup tables and to make finding users with same passwords impossible. With no salt, two
identical passwords would have identical hashes and that's easy to spot, so salted hashes prevent
a Birthday Attack. The example above is a common way of salting, but still uses fast hashes.
28. Password cracking tools like the Hashcat directly support this simple concatenation and as the
attacker has both hash and the salt from the database, cracking salted passwords by brute-force or
dictionary attacks means no real problem for them. Speed-wise, it's just like there was no salt
used. But as stated earlier the main task for the salt is to prevent Birthday Attacks and querying
pre-computed lookup tables and that means it does not matter that much. Just a lil bit.
29. Michal Špaček @spazef0rze
HMAC(password, salt)
hash_hmac(sha512, password, salt)
Slightly better salting is implemented in HMAC (Hash-based Message Authentication Code)
algorithm. First, XOR is applied to the salt, then the salt is concatenated to the password, hashed
and then once again. It could be used for password hashing if slow hashing function is used.
30. The choice of slow hashing function is important but even the SHA-512 is just 10× slower than
SHA-256, 30× slower than SHA-1 and 80× slower than MD5. So not that slow. Ultimately, HMAC is
not the best choice for secure password hashing. But… there must be something better.
31. Michal Špaček @spazef0rze
bcrypt!
Blowfish hashing
Oh, yeah, there is! One such algorithm is bcrypt, sometimes also called Blowfish hashing. The
function is relatively slow, has built-in support for salt and even multiple hashing. The algorithm
has a parameter called cost which says how long the whole password hashing thing should take.
32. Michal Špaček @spazef0rze
crypt() salt=$2y$…
password_hash()
password_verify()
In PHP, bcrypt is supported by the crypt(), if salt is prefixed with $2y$. This prefix is supported
starting with PHP 5.3.7, don't use earlier versions. Also, don't use $2a$ and $2x$ prefixes.
PHP 5.5 brings nice functions for password hashing, also available as a library for older versions.
33. Michal Špaček @spazef0rze
scrypt
PBKDF2
Some other good password hashing algorithms include scrypt and PBKDF2 (Password-Based
Key Derivation Function 2). scrypt is far more secure against hardware brute-force attacks than
bcrypt by using much more memory, but is available for PHP only as a third-party extension or
library. Beginning with PHP 5.5 built-in function hash_pbkdf2() is also available but the rule
here is to use scrypt for password hashing whenever you can. If you can't, use bcrypt. Use
PBKDF2 only if you can't use bcrypt (and you always can) and don't use anything else.
34. Never send passwords in e-mail messages. Never, not even after sign-up. Users don't change
passwords, they use the original generated one and they keep them in their mailbox. And as
you've seen, mailbox is not a secure storage in the long term. All a user has to do to get into
troubles is to lose their smartphone or laptop. Also, e-mails are routed through servers with
mostly unencrypted drives and they usually talk to each other using unencrypted connections.
To add an extra layer of protection encrypt the hash and the salt with a symmetric cipher
such as AES-256. Once the application is hit with an SQL Injection or similar attack the key stored
in the configuration remains secret and the hashes can't be decrypted easily so passwords cannot
be cracked. Encryption won't help if the system is fully compromised and attacker gains access to
the key as well but that's not the case very often. Passwords in your database are still properly
hashed making them safe, but anything you can do to make attacker's life harder is a good thing.
35. There's more than just a password hashing to make passwords secure. Never transmit passwords
from the browser over plain HTTP, use HTTPS to prevent wiretapping. Also use a certificate signed
by a trusted certification authority so that users don't see those strange warnings. The form with
a password input field should also be transferred over HTTPS to make sure the attacker can't
change the action attribute of the form or inject some malicious JavaScript stealing passwords.
36. Never send passwords in e-mail messages. Never, not even after sign-up. Users don't change
passwords, they use the original generated one and they keep them in their mailbox. And as
you've seen, mailbox is not a secure storage in the long term. All a user has to do to get into
troubles is to lose their smartphone or laptop. Also, e-mails are routed through servers with
mostly unencrypted drives and they usually talk to each other using unencrypted connections.
37. If your site has a Forgotten password feature never send the password by e-mail. You don't know
the password anyway because you keep only hashes in your database, right? Only send a link
which will expire in one hour, with a random token which is different for every password reset
attempt. The link will take the user to a page where they can set their new password. Again, do not
send the new password by e-mail. If your site allows users to register multiple accounts with one
e-mail address always display the same message whenever user enters correct e-mail address for
resetting the password or not. This way the attacker can't enumerate e-mails in your database.
Rychlosti hashovacích funkcí viz oclHashcat benchmarking: http://thepasswordproject.com/oclhashcat_benchmarking
CRYPT_BLOWFISH security fix details: http://www.php.net/security/crypt_blowfish.php password_* funkce pro PHP 5.3.7 a novější: https://github.com/ircmaxell/password_compat