Security Tip: Stop Using MD5 and SHA-1!

[Tip #87] MD5 is like a cockroach - it's persistent and pops up everywhere, but one thing is very clear: you need to stop using it (and SHA-1 too)!

Security Tip: Stop Using MD5 and SHA-1!

There were some interesting discussions over on the socials this past week, all spurred from the proposed deprecation of the md5(), sha1(), md5_file() and sha1_file() functions.

Deprecating these methods wouldn't have prevented you from using MD5 and SHA-1 in your code, it's just about those specific helper aliases. PHP has the hash($algo, $value) and hash_file($algo, $filename) methods, which provide access to all of the supported hashing algorithms. In fact, this is the only way to use the secure hashing algos, which is why MD5 and SHA-1 are still used so frequently!

Unfortunately, it looks like the vote will fail and they won't be deprecated, however since I'm still strongly in favour of deprecating these functions, I thought this would be a good opportunity to look at the more secure alternatives to MD5 and SHA-1.

  1. Password Hashes

MD5 and SHA-1 should never be used for hashing passwords, even if they are salted. In fact, no raw hashing algorithm should be used for passwords. They are far too easy to crack using a brute-force attack, even when salted, and offer virtually no protection.

Use bcrypt, a dedicated password-hashing algorithm, with either Laravel's Hash facade, or PHP's password_hash() method directly. If you still have passwords which aren't bcrypt, you should rehash them to keep them secure.

return Hash::make($password);
  1. Checksums

Generating checksum hashes for externally shared files, so users can verify the file hasn't been modified or corrupted.

Both MD5 and SHA-1 are vulnerable to hash collisions (where two different inputs produce the same hash), which may allow an attacker to replace legitimate files verified by a checksum with malicious files that share the same checksum.

Use SHA-256 (or SHA-512) to generate a secure hash through hash_file():

return hash_file('sha256', 'example.txt');

If you don't need a secure hash, just a method to check for file corruption or a unique value for cache busting, then MD5/SHA-1 will work, but you should ideally use a dedicated checksum algorithm, such as CRC-32 to calculate a quick checksum:

return hash_file('crc32b', 'example.txt');
  1. (Cryptographic) Signatures

Similar to checksums, but with the addition of a secret key to prevent forged signatures. Often used in APIs and webhooks to validate payloads.

MD5 and SHA-1 should not be used for any cryptographic purposes, and are unsuitable for any form of cryptographic signature. They are vulnerable to collisions, and brute-forcing, and cannot be trusted to protect the values.

Use Hash-based Message Authentication Code (HMAC) with SHA-256 to generate a secure hash (learn more):

return hash_hmac($algo, $plaintext, $secretKey);
  1. Unique Keys

Generating unique keys from complex data to prevent collisions, such as cache keys, rate limiter keys, compiled file caches, etc.

MD5/SHA-1 is safe for this usage, as you just need uniqueness and not security, however the xxHash algorithm provides a much faster alternative, which could have useful performance improvements for your app. (This is also why you want crc32 for checksums.)

Switch to XXH128 to gain speed improvements in your code:

return hash('xxh128', $value);

As a side note, Laravel has an open PR discussing switching from MD5 to XXH128.

  1. Random Strings

MD5/SHA-1 should never be used to generate random strings, and especially not with code like md5(time()), md5(rand()), substr(md5($user->email), 8, 16), etc. (Yes, I've seen all of these...)

Use cryptographically secure randomness with random_bytes(), Str::random(), PHP's Randomizer class, or my Random package.

return Str::random(32);
  1. Legacy Support

If you need to support third-party systems, avoid breaking changes, or maintain continuity between legacy and modern systems, then you may need to stick with MD5/SHA-1 for now. This is especially true for things like third-party APIs which use MD5 for webhook verification (this is very common).

If you're still using MD5 or SHA-1, plan a safe upgrade path to secure and/or faster alternatives (like rehashing passwords) so you can deprecate MD5 and SHA-1 from your own code. Also, if you're working with third-parties who need those functions, remind them to upgrade to a secure alternative.

Discussion Topic:
Do a code search for md5 and sha1 in your projects right now, and share in the comments below or on socials:

Did you find anything?
Is it used for some form of security?
Is there a better alternative you could be using, or do you need these functions for a specific reason?