WordPress Password Security Follow-up

I wrote a blog post about on improving password security in WordPress and the Roots team created a plugin called wp-password-bcrypt to improve it a few weeks ago.

Late Friday night, a few people (including myself) got into a Twitter argument about these security issues. Andrew Nacin, a Lead Developer of WordPress, ended up tweeting this:

The main disagreement between Nacin and myself was how I characterized (or mis-characterized) the password encryption algorithm that WordPress uses. Here’s how I described it:

MD5 may sound familiar. It’s the hashing function that WordPress uses. In fairness to WordPress, they combine MD5 with a salt.

Unfortunately, MD5 + salting is also broken and this has been known for a long time.

Being wrong

Saying "MD5 + salting" was an informal way of describing the algorithm and wasn’t literally meant to be pseudocode as Nacin mentioned twice.

Regardless, Nacin was correct that I was wrong about this. I definitely mis-characterized the algorithm that WordPress uses by simplifying it down to "MD5 + salting". My main argument against the current algorithm was "it’s bad because MD5 is bad".

MD5 is an insecure/broken hashing function. But that doesn’t really matter in this case. What I failed to accurately describe was that the library WP uses, phpass, has a much more secure algorithm which employs key stretching via 8192 iterations.

This error I made resulted in WordPress appearing much more insecure (in terms of password cracking) than it is in reality. The difference between md5(password + salt) and bcrypt is night and day. The former is basically insane in 2016 (as Nacin even said). The difference between the current algorithm and bcrypt is a lot closer in terms of security than I described.

phpass is a respected library with strong algorithms and no one should think that WordPress custom-made an ineffective solution. However, that’s not the end of it.

Alarmist

Andrew Nacin also said my post was alarmist. I’m fine with that. Hopefully it means more attention is brought to this issue. So didn’t I just admit I was wrong? What’s the actual issue here?

Yeah, I got some details wrong and made the problem seem worse than it is. But it’s still something that can easily be improved.

Both Nacin and Ryan McCue took issue with my errors without really addressing the overall problem:

WordPress is not switching to a better alternative which would improve its user’s security.

That being said, what’s at stake here? I’ve been talking about password security but this is just security against offline attacks. Here’s how these attacks work:

  1. Attacker gets access to your server or database.
  2. They try to brute-force the password hashes.

The harder you make the 2nd step, the better your security is. Obviously you’re already in deep trouble if the above steps happen. All other plain text data in your database is already compromised and the only thing that’s left is the password hashes. But protecting your users’ passwords is still important.

Context

WordPress’ choice of phpass’ portable algorithm in 2008 was fine. Drupal and phpBB also adopted it. What’s interesting is how Drupal’s and WordPress’ implementations differ. Both were from about 8 years ago (2008) and here they are:

Drupal did a great job documenting exactly what the library did and explaining the various functions and concepts. They talk about salts and password stretching. You’ll also notice they defaulted to a hash count/cost of 14 along with this comment:

The standard log2 number of iterations for password stretching. This should increase by 1 at least every other Drupal version in order to counteract increases in the speed and power of computers available to crack the hashes.

Key stretching algorithms are strong against attacks because you can increase the cost factor as computing power increases. The general rule is to increase the cost every 1.5-2 years to keep up with Moore’s Law.

So Drupal started with a cost of 14 vs WordPress’ 8 and made a note to increase them along with versions. What are they at now? 16.

Meanwhile WordPress started with a default of 8 and that has never changed in over 8 years. Note that a cost of 8 equals the 8192 iterations mentioned above.

The present

So what should WordPress be using now? We already know the answer to that and it’s bcrypt. WP should automatically default to bcrypt for sites running on PHP >= 5.3.7 (at least, and definitely for >= 5.5).

bcrypt is not perfect. scrypt is probably better. And Argon2 probably even better than that. But only bcrypt is included in PHP so it’s currently the best option.

So how much does this matter? I’ll defer to Anthony Ferrara (ircmaxell) who’s the author of the great password_compat library (which WordPress could use for PHP >= 5.3.7). Quotes are taken from this Stack Overflow answer: http://stackoverflow.com/a/16044003.

Is the phpass portable algorithm bad?

The short answer is no, it’s not bad. It offers pretty good security. If you have code on this right now, I wouldn’t be in a rush to get off it. It’s adequate for most usages. But with that said, there are far better alternatives if you were starting a new project that I wouldn’t pick it.

Should it be avoided?

For new projects, absolutely. It’s not that it’s bad. It isn’t. It’s that there are demonstrably stronger algorithms out there (by orders of magnitude). So why not use them?

And the bottom line:

So if you’re writing new code, without a doubt use bcrypt. If you have phpass or pbkdf2 in production now, you may want to upgrade, but it’s not a clear cut "you’re significantly vulnerable".

Note that his answer was from 2013 and he included some numbers from a 2012 security conference on password cracking (source):

  • md5($password)

    • 180 BILLION guesses per second
    • 9.4 Hours – All possible 8 character passwords
  • sha1($password)

    • 61 BILLION guesses per second
    • 27 Hours – All possible 8 character passwords
  • md5crypt (which is very similar to phpass with a cost of 10):

    • 77 Million guesses per second
    • 2.5 Years – All possible 8 character passwords
  • bcrypt with a cost of 5

    • 71 Thousand guesses per second
    • 2700 Years – All possible 8 character passwords

Couple things of note here:

  1. These numbers are from 2012. They are obviously much faster now and would take less time.
  2. md5crypt which is very similar to phpass with a cost of 10. WordPress uses 8 which would make that even faster.
  3. bcrypt by default in PHP uses a cost of 10. The cost number is exponential in terms of "iterations". So thats 2^10 vs 2^5.

Winners and losers

The best thing about being publicly wrong is Brian Krogsgard subtweeting a scorecard of a Twitter argument.

I normally wouldn’t care about a tweet like that but I found the underlying message pretty awful. I really don’t want to see what WordPress looks like if no one ever debates practices with core team developers.

End result

So where do we stand after all of this? Mostly the same as before.

If you’re on PHP >= 5.5 then use our bcrypt plugin (or another one that works on >= 5.3.7). You’ll improve your site’s security.

Hopefully this has brought some attention to the issue and people have learned more about password security.

Learning material

If you’re interested learning more about passwords, encryption, hash functions, etc. here are some good resources I came across:

Read the discussion on our Discourse

Get our latest updates & occasional tips on building better WordPress sites

Follow @rootswp on Twitter