Loading episodes…
0:00 0:00

A Developer's Guide to Secure Password Storage: From Plain Text to S-Tier

00:00
BACK TO HOME

A Developer's Guide to Secure Password Storage: From Plain Text to S-Tier

10xTeam November 28, 2025 7 min read

If you’re building a product that requires user authentication, you inevitably have to deal with storing passwords. This fundamental task, however, opens your application to significant security risks. A database breach could lead to stolen passwords, immense reputational damage, and a catastrophic loss of user trust.

So, how do you store passwords securely? Let’s explore the options, starting from the worst possible method and progressively building up to a much more robust and secure solution.

The F-Tier: Storing Passwords in Plain Text

The absolute worst way to store passwords is as normal data in a regular database column, alongside other user information. This is known as storing passwords in plain text.

This approach is critically flawed. If a hacker gains access to your database, they can steal every single password effortlessly. Security is all about creating multiple lines of defense. Storing passwords in plain text offers zero defense. If your database is breached, the game is over. And database breaches happen with alarming frequency. This method is, without a doubt, F-Tier.

The D-Tier: Encrypting Passwords

If you’ve read about encryption, you might think the next logical step is to encrypt the passwords. This is certainly an improvement. When an attacker breaks into your database, they are met with gibberish instead of useful information.

However, this method has a crucial weakness. If the attacker also manages to steal the decryption key, they can decrypt all the passwords, and you are right back in F-Tier territory. While it’s better than leaving passwords in the open, an attacker who has already gained access to your database may not find it much more difficult to steal a decryption key from an adjacent server or a configuration file.

Furthermore, storing passwords in a way that allows them to be retrieved introduces the risk of an inside job. A malicious employee with privileged access could decrypt user passwords for nefarious purposes. The extra protection helps, but this is still D-Tier.

The C-Tier: Introducing Hashing

The key insight to better security is realizing that we only need to verify that a user has entered the correct password; we don’t need to know the password itself. This is made possible through a one-way cryptographic technique known as hashing.

Hashing generates a unique, fixed-size fingerprint from an input password. This process allows us to verify a password in the future without ever being able to recover the original password from its fingerprint.

How does it work?

  1. Sign-up: When a user creates an account, we take the password they provide, generate a hash from it, and store only the hash in the database.
  2. Log-in: When the user tries to log in, we take the password they just typed, run it through the exact same hashing process, and compare the resulting hash to the one stored in our database.

If the hashes match, it is overwhelmingly likely that the user typed the correct password. Thanks to the power of hashing, we can validate a user’s identity without ever storing their actual password.

The Magic of Hashing

Hashing relies on two core principles:

  1. One-Way Function: The process of hashing involves aggressively mixing and scrambling the input data. It’s like mixing three different colors of paint to create a shade of brown. From the resulting brown, it’s nearly impossible to determine the original three colors. Similarly, you cannot reverse-engineer a password from its hash. Once you hash, you can’t un-hash.

  2. Collision Resistance: A good hash function ensures that even a tiny change in the input results in a completely different output hash. For robust hash functions, there is no known way to intentionally create two different inputs that produce the same hash (a “hash collision”) without resorting to brute-force guessing millions or billions of strings.

Note on Hash Functions: Picking the right hash function is critical. Older algorithms like MD5 and SHA-1 were once considered secure, but cryptographic progress has rendered them obsolete. For example, researchers can now generate an MD5 collision on a standard laptop in about a second. Modern applications should use stronger functions like the SHA-2 family.

With hashing, we no longer have a single key that can unlock the entire password table. This is a definite improvement, landing this technique in the C-Tier.

The Problem: Dictionary and Rainbow Table Attacks

However, a major vulnerability remains. Many people use extremely common and weak passwords, like password123 or qwerty. An attacker with access to your database can pre-compute the hashes for millions of common passwords. They can then compare this list to the hashes in your database to find matches. This is called a dictionary attack.

To make this process even faster, attackers use pre-computed databases of hashes known as rainbow tables. These massive tables allow them to find password matches almost instantly.

The B-Tier: Adding a Pinch of Salt

To defend against rainbow tables, we can use a technique called salting.

When a user signs up, instead of directly hashing their password, we first generate a short, random string called a salt. We then append this salt to the password before running the hash function. Finally, we store the salt alongside the hashed password in the database.

// Example Data Structure
{
  "username": "alex",
  "password_hash": "a8f5f167f44f4964e6c998dee827110c", // hash(salt + password)
  "salt": "qR8!n$2*pB"
}

During login, we retrieve the user’s salt, append it to the password they entered, and hash the combined string to see if it matches the stored hash.

This makes pre-computed rainbow tables useless because their hashes were generated without salts. It also ensures that two users with the same password will have different hashes in the database, as each will have a unique salt.

But why is this still B-Tier? Because it doesn’t stop dictionary attacks. An attacker can still take their list of common passwords, apply the user’s salt, and try to find a match one by one. With modern hardware like GPUs, they can compute billions of hashes per second, making this a very real threat.

The A-Tier: Deliberately Slow Hashing

The solution is to use a specialized password hashing function that is deliberately slow.

Standard hash functions like SHA-2 are designed for speed. Password-specific hashing functions like bcrypt, scrypt, and Argon2 are different. They come with salting built-in and, more importantly, are designed to be slow, power-hungry, and memory-intensive.

This slowness is a feature, not a bug. It’s designed to combat the overwhelming power of modern hardware. The billions of guesses per second an attacker could once make are slowed down to mere thousands, or even less. You can configure the level of slowness using a parameter known as the work factor.

With a sufficiently high work factor, it becomes computationally infeasible for an attacker to break anything but the weakest passwords. The goal of security isn’t to be completely immune to attacks—that’s impossible. It’s to hinder attackers so much that they give up and go elsewhere.

A Look at Bcrypt

The output of a bcrypt hash contains everything you need to verify a password:

$2a$12$cTj.9U/Tj.9U/Tj.9U/Tj.uY2oV5f6g7h8i9j0k1l2m3n4o5p6q7

  • $2a$: The bcrypt algorithm identifier.
  • 12$: The work factor (cost). This is exponential; a work factor of 13 is twice as slow as 12.
  • cTj.9U/Tj.9U/Tj.9U/Tj.u: The 22-character salt.
  • Y2oV5f6g7h8i9j0k1l2m3n4o5p6q7: The 31-character hash.

When bcrypt was first published, the recommended work factor was 6. On a modern laptop, that takes milliseconds. Today, a work factor of 12 to 15 is more common, which can take over a second to compute. This dramatic slowdown is our best defense against brute-force attacks.

The S-Tier: The No-Password Strategy

So, is there an even higher tier? Yes, but it’s a bit of a trick answer. The S-Tier of password storage is not storing passwords at all.

As we’ve learned in this article, storing passwords is a tricky business. A better approach is to avoid it entirely by using third-party authentication services like “Sign in with Google,” “Sign in with Facebook,” or other identity providers.

By delegating authentication to an established platform, you offer more convenience to your users and get to sleep better at night, knowing your system contains no passwords to steal.


Join the 10xdev Community

Subscribe and get 8+ free PDFs that contain detailed roadmaps with recommended learning periods for each programming language or field, along with links to free resources such as books, YouTube tutorials, and courses with certificates.

Audio Interrupted

We lost the audio stream. Retry with shorter sentences?