Password storage is a common problem that every developer needs to solve at some point in their career. Often, we rely upon frameworks and libraries to do it for us. But do they get it right?
How should passwords be stored? How are they going to be attacked? All these questions (and more) will be answered. This session will dive head first into password storage and all aspects surrounding it. We’ll cover some common misconceptions and dangerous mistakes. We’ll also explore some of the best available tools to solve the problem, and go into why they are the best. Finally, we’ll look at some of the tools that attackers will use to attempt to extract plain text passwords.
We’ll explore each point from both angles: the pragmatic developer and the attacker. For the safety and security of your users, make sure that you know how to securely store their passwords. It’s not just the right thing to do, but it is negligent not to!
2. “Anyone, from the most
clueless amateur to the
best cryptographer, can
create an algorithm that
he himself can't break.”
- Bruce Schneier
3. Github URL
Follow Along:
github.com/ircmaxell/password-bad-web-app
A "Bad Web App"
- Has Known Vulnerabilities
- Only Use For Education!!!
- Requires only Apache + PHP
- Has Composer Dependencies
14. What's A Cryptographic Hash?
Like a fingerprint.
One-way.
- Easy and efficient to compute
- Very inefficient to reverse
- (Practically impossible)
- Very hard to create collision
- (new input with same output)
15. MD5
What's the problem now?
SQL-Injection still gives us hash
But the hash is one-way, how can we attack it?
19. Lookup Table
Google is a great example
Maps hash to password directly
Database Table:
hash | password
--------------+-----------
"5f4dcc3b..." | "password"
"acbd18db..." | "foo"
20. Lookup Table
Lookups are CPU efficient.
Require a LOT of storage space
- (Very space inefficient)
All passwords <= 7 chars (95^7, 70 Trillion)
Requires 1.5 PetaBytes
- In Most Optimal Storage Format
30. Rainbow Table
Time/Space Tradeoff
- Slower than a Lookup Table
- Uses Much less storage
Most (99.9%) passwords <= 7 chars
Requires only 64 GB
- Chain length of 71,000
33. Salted MD5
git checkout salted-md5
Uses the MD5 Cryptographic Hash function.
But adds a random salt UNIQUE per user.
md5($salt . $password)
hash('md5', $salt . $password)
34. Salts
Must be unique!
- Per Hash
- Globally
Should be random
- Strong!!!
- Reasonably long (at least 64 bits)
35. Salted MD5
What's the problem now?
SQL-Injection still gives us hash
- And the salt
But the salt defeats rainbow tables...
38. What's A Cryptographic Hash?
Like a fingerprint.
One-way.
- Easy and efficient to compute
- Very inefficient to reverse
- (Practically impossible)
- Very hard to create collision
- (new input with same output)
39. What's A Cryptographic Hash?
Like a fingerprint.
One-way.
- Easy and efficient to compute
- Very inefficient to reverse
- (Practically impossible)
- Very hard to create collision
- (new input with same output)
41. Brute Forcing
Several Tools Available
- John The Ripper
- OCIHashCat
A Lot Faster Than You May Think
42. Brute Forcing
Multiple Ways To Attack
- Mask Based (permutations)
- Dictionary Based
- Combinator Based
- Combinations of dictionary words
- Fingerprint Based
- Combinators applied with permutations
- Rule Based
- Takes input password and transforms it
43. Brute Forcing
Salted MD5
2012 Macbook Pro:
- md5: 33 million per second
- sha256: 20 million per second
Mask Attack:
6 char passwords: 5 hours
7 char passwords: 22 days
Entire English Language: 1.8 seconds
"LEET" Permutations: 1 hour
49. MD5 IS Broken!
But No Other Primitive Hash Is Not!!!
sha1≈ md5
sha256 ≈ md5
sha512 ≈ md5
whirlpool ≈ md5
ALL raw primitive hashes are broken for
password storage.
51. Iterated MD5
git checkout iterated-md5
Uses the MD5 Cryptographic Hash function.
But adds a random salt UNIQUE per user.
And iterates a lot of times
do {
$h = md5($h . $salt . $password)
} while($i++ < 1000);
59. BCrypt
git checkout bcrypt
Uses the standard BCrypt algo
- based on Blowfish cipher
Same execution time,
Much harder to run on GPU
crypt $2a$
60.
61. Brute Forcing
BCrypt
25 GPU Cluster
- BCrypt: 70,000 per second
6 char passwords: 120 days
7 char passwords: 31 years
8 char passwords: 3000 years
Entire English Language: 14 minutes
62. A Note On Cost
BCrypt accepts a "cost" parameter
Must be tuned per server!
- Target about 0.1 to 0.25 second runtime
- Cost of 10 is a good baseline
- Cost of 11 or 12 is better
- Only if you have good hardware.
63. PHP 5.5 Password Hashing API
git checkout password-compat
A thin wrapper over crypt()
- Simplifies implmentation
- Strong random salt generation
- Can specify cost as int option
password_hash($pass, $algo, [$opts])
password_verify($pass, $hash)
github.com/ircmaxell/password_compat
66. Encrypted BCrypt
git checkout bcrypt-with-encryption
Hash with BCrypt,
Then encrypt result with AES-128.
Requires key storage for the app.
- Not trivial
Use only if needed!
- BCrypt alone is typically sufficient
67.
68. Brute Forcing
Encrypted BCrypt
Attack requires low level server compromise!
- SQL Injection is not enough!
localhost/codeinject
- Simulates code injection that reads source
Any low level compromise
Is No Worse than raw BCrypt
- BCrypt is the baseline.
71. The Future
scrypt
- Sequential Memory Hard
- Uses a LOT of memory (> 4mb / hash)
- MUCH Harder to brute-force than bcrypt
- IFF setup correctly
72. The Future
Password Hashing Competition
- Currently being setup
- Aims to pick "standard" password hashing
algorithm
- A community effort
73. The Future
Brute Forcing Word Lists
- Complex combinations of words
- "horse correct battery staple"
Brute Forcing Grammar
- "I don't want no cookies"
Brute Forcing Structures
- URLs, Email Addresses, URLs, etc
74. “Few false ideas have more firmly
gripped the minds of so many
intelligent men than the one
that, if they just tried, they could
invent a cipher that no one could
break.”
- David Kahn