Simply Secure PHP Cryptography
paragonie.com
paragonie.com
This! I'm still seeing code snippets on StackOverflow that use hashing for password storage and queries without prepared statements.
I think at the moment that is still a weak spot of PHP.
Edit: my mistake. I was refering to weak hashes like md5 and sha1 or 'home brew' hashing.
As opposed to...?
For example, I see a lot of this construction in proprietary code:
$passwordHash = md5(md5($password) . md5($salt));
if ($storedHash == $passwordHash) {
// Authenticated successfully
}
I'm quick to find these offending snippets and migrate our clients to use password_hash() and password_verify(). SELECT * FROM user WHERE username = '$username' AND password_hash = MD5('$password')It is markedly less common, but still quite common, if not pervasive like it used to be. PHP apps are dramatically more likely to have security vulnerabilities of any sort. It is a running joke we have that one of our recommendations to remediate security issues with PHP is to "rewrite in a different language". For whatever reason PHP has a history of encouraging vulnerable code. Even in good shops. PHP itself isn't really to blame (it is, of course much less likely for an experienced shop to write crappy PHP... but they probably wouldn't pick PHP to begin with).
Using bcrypt/scrypt/Argon2id does.
But at least, if you want to roll your own password hashing, do it right: use hmac, salting, stretching and a decent hash function - or use bcrypt/scrypt and save yourself a few headaches.
[1]: https://en.wikipedia.org/wiki/MD5#Preimage_vulnerability
If you think I'm wrong, I will gladly admit so, just tell me what the $password is here:
if (md5(md5($password)) == 'c9876599e5e54aa12962ae1fe7b0f752') ...An attacker doesn't care about your password so much as they care about getting 50-80% of the passwords on the system, the majority of which are going to be "password123" or some other garbage you can find in a dictionary attack. If you use something like Bcrypt or Scrypt then running your dictionary cracker becomes a real ordeal, it will take a long time to grind through those entries and find matches. With MD5 it's a joke, you can do most of the common ones in seconds and the trickier variants within hours.
Hashcat (https://hashcat.net/hashcat/) can and will make short work of your double MD5 nonsense.
Additionally, if I can find a bit of text that hashes the same I don't care what the original password was. I have a key that works.
Another thing you should do is not allow common or short passwords. That includes "password123". That alone will immediately elevate your security.
> Additionally, if I can find a bit of text that hashes the same I don't care what the original password was. I have a key that works
And you clearly don't understand how the collusion vulnerability works. You can't create one with a given hash. You carefully craft two documents that hash to the same hash, which you don't know in advance. Again, you can prove me wrong by doing just that to the hash in the code snippet.
Cryptographers nowadays are recommending PKBDF2 (essentially iterated hashing with the hash algorithm of your choice) with at least 100,000 rounds. And it's considered to by far the weakest of "modern" password hashing approaches, behind bcrypt, scrypt, and Argon2 (in that order).
Your double-MD5 is garbage, and nobody is going to bother wasting their time breaking it because it's a bullshit challenge. If you used a strong, unique password, you've missed the point, because users in the real world don't. If you used a weak password, we have a few billion points of empirical data that contradict you, so why bother installing hashcat and mucking about with password cracking rules when anyone paying attention for the past ten years knows what the outcome is going to be?
I actually do use PKBDF2 / Bcrypt in real world projects. My original comment was entirely about MD5 not really being broken, just too fast.
> because users in the real world don't.
No, you missed the point, and I wrote about it specifically. You should not allow weak / common / short passwords.
You started off saying MD5 is fine, then backed off to saying it's fine with a salt, then fine with two rounds, then suggested 1,000 is okay, now we're at 100,000. At what point do you stop making excuses and acknowledge that your original advice was garbage, and backpedaling repeatedly is not helping your case?
Further, it is impossible to categorically prevent weak passwords. You can impose length restrictions. You can disallow common passwords. You can require special characters. But people's ability to come up with weak, pattern-based passwords fundamentally outperforms our ability to stop them, and at some point restrictions become so burdensome that people stop signing up for your app altogether.
"Just block weak passwords" is ridiculous on its face and you either know it and are arguing simply to save face, or you don't know it and are infuriatingly overconfident for your level of incompetence. I'm past the point of caring which.
Even SHA1, which is a much harder hash to compute, can be processed at trillions of hashes per second on some hardware. If you did a million cycles of SHA1, guess what? That thing can still crack a million guesses per second.
Bcrypt has a difficulty number you can pin at a level that's uncomfortably high. It may take 200ms to verify a password if you really crank it. That means you can't do thousands of hashes per second, but you're stuck doing maybe a thousand hashes per minute. You can't dictionary attack that.
I know how the collision vulnerability works. People have been creating MD5 collisions for fun for a while now, unconcerned with the original hash. If they focused their effort on matching hashes, they could probably do it by exploiting fundamental weaknesses in the MD5 hash system itself.
At this point a sufficiently robust SAT solver can probably crack it.
All your hand-waving about disallowing easy passwords doesn't matter. If you add restrictions, people find ways around them. It also doesn't matter if you make passwords incrementally harder if someone can crack them easily. Their computer doesn't care if they set it to search ten characters instead of eight, modern crackers are pretty efficient to fairly intimidating lengths.
I don't think you have any clue what you're talking about. Do a million sequential rounds of MD5 on your CPU and measure how long it takes. I guarantee you, it's not zero. Not even close.
High-end FPGAs can smash through SHA1 at rates of billions per second and MD5 is not even that complicated. A million rounds is not as hard as Bcrypt cranked up to a sufficiently robust level.
I can't emphasize this enough.
Libsodium was Frank Denis's project, which was spawned by NaCl by cryptographers Dan Bernstein, Tanja Lange, and Peter Schwabe.
The participants who voted on the RFC, for the most part, were involved in the technical discussions over the past two years since I first mentioned the notion of doing so (before the PHP 7.0 release).
Similarly, there were 13 people who contributed to the libsodium-php repository (ext/libsodium in PECL). Every single one of them had to consent to relicensing the extension to easily get merged into PHP, and we all did.
I often joke that I'm the worst C developer in all of infosec, but there's some truth to that when it comes to modifying the PHP core.
My main role in the ext/sodium project was saying, "We should do this," and somehow getting people to listen.
It's identical to what was merged to PHP 7.2 (actually a bit better since some pull requests haven't been merged to php-src yet).
I don't believe re-implementing the wheel like that is a 'modern security practice'. I asked why they did that instead of using robust, well tested and well supported libraries and did not get a satisfactory answer.
While it's not the author's project (I think?) he is still part of the company, and I'd hope such a security-focused organization wouldn't have done something like that.
A lot has changed since you last looked at it, and a lot will change before the v2.0.0 rewrite is complete.
I'm glad to hear things have changed in the code however, and wish you the best with the rewrite.
I don't much care one way or the other about whether it's OK to try to take people down a peg, but I do care very much when people do that and then try to get away with pretending that's not what they're doing.