
Likely the most painful password hashing discussion you'll ever read - sarciszewski
https://scott.arciszewski.me/misc/Linkedin/Fail.html
======
Alupis
For the people not understanding why this discussion is a problem, in
synopsis:

In order for a server to use encrypted passwords for authentication, the
server must have access to the decryption key -- which means an attacker has
access to your decryption key if they can compromise your box. Furthermore, if
they don't get your decryption key, but they get your database dump -- they
can then just brute your db and decrypt the passwords. They can do this
because encryption is, by design, reversible. Encrypting passwords is almost
as bad as storing in plain text.

Cryptographically hashing a password is the only way to go. When you
cryptographically hash a password, using a known library that has been tested
and written by actual cryptographers with passwords/authentication in mind
(like bcrypt, etc -- no, sha's and md5's are _not_ safe to use) - you get a
one-direction algorithm in that a password goes in, is digested, and a fixed-
length hash output comes out. There is no way to reverse this hash back into
the original input. Adding salt(s) combats people making rainbow tables
against your implementation, as they then would need to know not only which
algorithm you are using, how many iterations it does, but also what your
salt(s) are (sometimes even varied every so many iterations). This makes it
almost impossible for someone to brute your leaked password database.

~~~
aerovistae
I was under the impression SHA256 _is_ valid...it's a cryptographic hash
function that hasn't had weaknesses identified yet. 40 iterations of that +
salting would suffice, no?

~~~
aerovistae
I do realize bcrypt is arguably the best option, but why is SHA not valid
also?

~~~
tptacek
Because it has no work factor. It's uniformly fast, which makes it very easy
to brute force. The general-purpose strong cryptographic hashes --- your
SHA2s, SHA3s, and BLAKE2s --- are all amenable to fast implementation on GPU.

What you need is a _password hash_ , not merely a cryptographic hash.

~~~
aerovistae
As noted above, this discussion prompted me to investigate my company's
methods, a fairly major US website, and I found they're using SHA-256 for 50
iterations with salting. Does that slow things down sufficiently, or is that
not comparable to the internal mechanism of bcrypt?

~~~
aerovistae
Company is stuck with ASP.

~~~
danielweber
If you change 50 to (say) 1000 you are getting most of the benefits.

The big problem you are trying to solve is "our password database just leaked;
how fast can attackers figure out the passwords?" Say you can run SHA in 1
microsecond, and 1000 iterations in 1 millisecond. Even though it's 1000x
slower, that's probably an unnoticeable difference as far as your performance
is concerned. (YMMV)

But, anyone trying to brute-force the passwords out of your database will now
have to do 1000x the work.

BTW, none of this will help you much if your users choose passwords like "abc"
or "password".

(IIRC scrypt lets you blow up in size as well as CPU, which makes GPUs
impractical for attacking.)

~~~
sarciszewski
Yep. [http://blog.ircmaxell.com/2014/03/why-i-dont-recommend-
scryp...](http://blog.ircmaxell.com/2014/03/why-i-dont-recommend-scrypt.html)

------
kazinator
"Do not use MD5" is repeated often in the discussion.

But are the weaknesses in MD5 relevant to hashing someone's 17 character
password?

The problem with MD5 is that it's possible to alter a document such that the
forged document still has the same digest. This is a problem for digital
signing.

That doesn't seem directly relevant to password hashing. Nobody wants to find
some 596 character string which has the same MD5 hash as your 17 character
password, even if it does work in its place.

Your password isn't a document that is being digitally signed by its hash for
the sake of certifying its authenticity. Nobody is even supposed to store that
document!

(Someone tell me where I went wrong, if so.)

~~~
peterwwillis
MD5 is vulnerable to collision and preimage attacks, which is bad for your
password hashes, period. Other functions provide additional computational
difficulty in doing exhaustive search of the keyspace. Even more functions
prevent hardware implementations from speeding up the process by requiring
excessive amounts of memory. This is why everyone suggests using bcrypt or
scrypt, or if they're not available, PBKDF2.

~~~
tedunangst
How are collisions and preimage attacks relevant for password hashes?

~~~
peterwwillis
In really simple terms, if either attack is possible, it potentially becomes
easier to find the password. If either attack's implementation becomes
slightly faster at finding the password than a full search of the key space,
this makes cracking easier.

Collisions are the most practical method of attack on password hashes. If you
develop a way to find collisions faster than an exhaustive search of the key
space, you shorten the time it takes to find a password that matches the hash.
Collisions have now been found on MD5 very quickly (on the order of hours).

Preimage attacks are not all that useful when password cracking because you
don't need to generate a _new_ message that hashes to the same hash you have
now, you're looking for _any_ message that hashes to the hash you have now.

Second preimage attacks aren't relevant because they assume you know the
password already and are looking for a new message/hash that match.

~~~
tedunangst
Collisions for arbitrary hashes? If I give you an MD5 hash, you can find a
collision within hours?

------
aqme28
_" either you can use md5 or base64, there are also many other encryption are
there.. md5 is very secure because it cannot be decrypted."_

I'd say this has to be a joke, but Poe's Law is a tricky thing.

~~~
sarciszewski
I'm pretty sure a couple of the posts here are tongue-in-cheek, but most of
them reek of cluelessness and tl;dr

------
orf
>> "MD5 is fine as long as your database doesn't get leaked and is the subject
of offline cracking (like adobe)"

Wow. So MD5 is fine as long as it isn't needed to protect the data. Looks like
a typical PHP discussion thread: plenty of misconceptions, a mix of of bad and
plain stupid advice with a pinch of SQL injectable code. Silly PHP developers.

~~~
danielweber
To be fair, there are a class of problems you solve by storing your passwords
behind a simple one-way function instead of as plaintext. I was asked earlier
this week to audit a system that made the old passwords available to the user
on their profile page. Using md5(), for all its shortcomings everyone has
mentioned here, would at least make this architecture mistake impossible.

------
milesf
The title of this post is lost on me. What's so painful about this discussion?
It's not that I'm stupid, it's just that I'm ignorant and don't know.

~~~
sarciszewski
It's painful because:

\- Bad advice is posted everywhere.

\- Good advice is disregarded because nobody reads the preceding posts in the
discussion.

------
sarciszewski
Warning: This might ruin your day. Also, don't let tptacek see this or he
might get very [angry/existential] (select appropriate).

~~~
Alupis
I'm floored by the amount of people with "fancy" titles from supposed
"consulting" companies in the link discussion.

The question was "I want to store password[s] in encrypted form." The answer
should have been immediately -- "you don't encrypt passwords, you hash
passwords using a well known, established, and tested cryptographic hashing
algorithm + a salt, damnit!"

~~~
owenmarshall
> The answer should have been immediately -- "you don't encrypt passwords, you
> hash passwords using a well known, established, and tested cryptographic
> hashing algorithm + a salt, damnit!"

Your answer is as wrong as anything posted on that discussion.

The correct answer is that you don't encrypt passwords. You _also_ don't hash
passwords with a salt.

Instead, you use a key derivation function such as PBKDF2, bcrypt, or scrypt.

~~~
Buttons840
You should hash passwords with a long random salt. You advocate using bcrypt,
and bcrypt requires a salt.

If you are not using a salt, then you are vulnerable to rainbow tables which
contain a few hundred thousand of the most common passwords. Even if your
hashing algorithm is slow and complex, there are still rudimentary rainbow
tables for them. If you haven't used a salt then with one quick scan at least
of few of your passwords will be revealed.

The effect of a long random salt is to make every password appear to longer to
the hashing algorithm. What's being hashed is the users password plus 20
random characters, and nobody has a rainbow table that contain those 20 random
characters. If your hashing algorithm, like bcrypt, accepts the salt as an
argument, then that makes things all the easier.

~~~
owenmarshall
> You should hash passwords (...)

You should _not_ hash passwords. You should _never_ hash a password.

You should use an appropriate key derivation function (bcrypt, scrypt,
PBKDF2). Key derivation functions are designed to address the issues you note
and many more.

Now, let me give a few choice tptacek quotes on this:

>The socialbookmarkosphere is abuzz with talk of “rainbow tables”(...) This
really freaks me out. If the “advanced” pole of your threat model is “rainbow
tables”, stop working on your social shopping cart calendar application right
now: I can’t trust you with my Reddit karma score, let alone my credit card
number.

> Rainbow tables are easy to beat. For each password, generate a random number
> [... and do what you said to do ...] Cool, huh? Yeah, and Unix crypt —-
> almost the lowest common denominator in security systems —- has had this
> feature since 1976. If this is news to you, you shouldn’t be designing
> password systems. Use someone else’s good one.

\---

I'm banging on this drum for a very simple reason: even if _you_ are smart
enough to know that salt+general purpose cryptographic hash function isn't
good enough, when you say "hash" programmers that _aren 't smart enough_ are
getting the wrong message.

And if you _do_ believe a "hashing algorithm with a long random salt" (which I
translate to "general-purpose cryptographic hash function, such as SHA/RIPEMD
+ a nonce") is sufficient to store a password... well, let's hope you don't.

------
lttlrck
I'm disappointed nobody suggested XOR

/s

~~~
CaveTech
But someone did suggest Base64!

~~~
tedunangst
Base64 does have one use: assume you need to store a plaintext password
because you need your service to login to another service. (Use oauth, yada
yada. Not everybody has it.) base64 coding passwords prevents support staff
from trivially seeing and learning passwords when poking about the database.
It's not to protect the password from bad people, it's to keep the good people
from accidentally learning something they don't want to know.

------
higherpurpose
Why mention md5 at this point, or even SHA1, when BLAKE2 exists? (assuming the
people there don't want SHA2 because of slower performance):
[https://blake2.net/](https://blake2.net/)

~~~
tptacek
Nothing in that thread annoyed me as much as this comment does. Yes, BLAKE2 is
trendy, and name-dropping is tempting. But BLAKE2 is _also not a password
hash_ , and can't safely be used to store authenticators for passwords.

~~~
peterwwillis
Right; it's a cryptographic hash. Technically there's no such thing as a
'password hash', only password KDFs and their results, which are composed
primarily by cryptographic hashes. I think the guy's point was that if you're
going to build a password KDF, you might as well use a hash function that's
less shitty than MD5 and SHA1.

~~~
tptacek
These people would disagree with you:

[https://password-hashing.net/](https://password-hashing.net/)

I was on your side for awhile, advocating that we just teach people about what
a KDF is, but my side lost.

~~~
peterwwillis
The only winning move is not to play.

------
boogerhead
Could a hacker learn the hash key and salting by opening a bunch of accounts
on the site before stealing the database, then comparing his known passwords
with the hashed values?

~~~
loumf
Salts are usually dependent on user details (like the username), so knowing
your salt doesn't help you with other passwords.

------
mobiuscog
The discussion is great - it shows all of the companies you should absolutely
avoid doing business with, as they have no sense of security.

------
squidmccactus
What about this is so bad to begin with? It looks like this is standard
industry practice now?

------
waitwhatt
It's linkedin. As expected.

------
cyphunk
in general anything coming from a php developer should be ignored. even
reading official php documentation when it comes to anything concerning
security should scare the shit out of grandmothers everywhere.

~~~
sarciszewski
The documentation has actually been going through a clean-up lately. For
example,
[http://php.net/manual/en/function.crypt.php#refsect1-functio...](http://php.net/manual/en/function.crypt.php#refsect1-function.crypt-
returnvalues)

Do you have any specific examples of bad security advice in the documentation?
I can try to raise hell with the doc maintainers and maybe even suggest an
amendment.

~~~
mercurial
I see that MySQL's documentation [1] recommends SHA2:

> Exploits for the MD5 and SHA-1 algorithms have become known. You may wish to
> consider using one of the other encryption functions described in this
> section instead, such as SHA2().

Further down:

> The PASSWORD() function is used by the authentication system in MySQL
> Server; you should not use it in your own applications. For that purpose,
> consider MD5() or SHA2() instead. Also see RFC 2195, section 2 (Challenge-
> Response Authentication Mechanism (CRAM)), for more information about
> handling passwords and authentication securely in your applications.

1: [http://dev.mysql.com/doc/refman/5.5/en/encryption-
functions....](http://dev.mysql.com/doc/refman/5.5/en/encryption-
functions.html#function_password)

~~~
sarciszewski
I may have voted this comment up, but it makes me feel very :(

Related, the only hashing algorithm supported by postgresql for authenticating
to the pgsql server is md5.

~~~
mercurial
Let's see:

> If you are at all concerned about password "sniffing" attacks then md5 is
> preferred. Plain password should always be avoided if possible. However, md5
> cannot be used with the db_user_namespace feature. If the connection is
> protected by SSL encryption then password can be used safely (though SSL
> certificate authentication might be a better choice if one is depending on
> using SSL).

Strongly implies that md5sum offers protection from an attacker sophisticated
enough to sniff passwords of the network. Snif.

