How EI stores passwords in databases

Sep 21, 2025

Up till now, I’ve been using MD5 encryption for storing passwords on the sites I’ve made. I know MD5 is not very robust or secure, but for my use cases, it was fine: a school management site, a personal bio website for one of my uncles, an online store without payment functionality for another uncle of mine who writes books, and an online record-keeping and employee management portal for another one of my uncles (I’m free labor), etc.

If you want to know how MD5 works, this Reddit comment by u/atoponce explains it beautifully:

Now, I thought I’d try out something different on EI (a project I’m working on – visit my first post for more context). I explored my options, came across tons of different solutions. I have coded EI in PHP and am using a MySQL database.

I looked into SHA1 and SHA256, but like MD5, they are cryptographic hash functions, not password hashing algorithms. They’re mainly designed for data integrity checks, which means they’re really fast (and therefore vulnerable to brute force and rainbow table attacks).

Then I went through the PHP documentation. PHP has a built-in function called password_hash(). It seemed like the best option. It’s specifically designed for hashing passwords. Looks good. Inside password_hash(), I had 4 options to choose from:

PASSWORD_BCRYPT is the default hashing algorithm used if you select PASSWORD_DEFAULT. It’s designed to be slow and resource-expensive for brute force attempts. Brute force is the main concern. As alf dot henrik at ascdevel dot com points out in the PHP documentation, an 8-character password using 96 possible characters would have:

96^8 = 7,213,895,789,824 ≈ 7.2 trillion combinations

If an attacker can test 100 billion passwords per second, it would take about:

7.2 trillion ÷ 100 billion = 72 seconds (a little over a minute)

to crack such a password with MD5 (or SHA1 & SHA256). That’s not much at all.

Now, with password_hash() using bcrypt, the hashing is intentionally slow. By default, bcrypt uses a cost factor of 10, which makes each hash take roughly 100ms to compute on a standard CPU. That means:

10 hashes per second, instead of 100 billion per second.

So, for the same 7.2 trillion combinations:

7.2 trillion ÷ 10 = 720 billion seconds ≈ 22,830 years

That’s the difference between MD5 and bcrypt in practice.

PASSWORD_ARGON2I and PASSWORD_ARGON2D are newer and more secure algorithms. But to keep things simple while still secure, I decided to go with PASSWORD_DEFAULT (aka bcrypt).

I use the $_POST method on my signup form, then a process_signup script runs. The bare password is stored in the variable $password. I then hash the password and store it like this:

1 $password_hash = password_hash($password, PASSWORD_DEFAULT);

The $password_hash is a 60-character long string. It makes sense to store it in the database as a 60-character field, but the PHP documentation suggests using 255 (or 256) length just in case the hash size changes in the future to keep up with new algorithms.

That’s a little explanation of how EI stores passwords in the database.

-faiq

ComputersEdgeItTech




Comments

Leave a comment