WhoDNS
All articles
Language: FA

Password Hashing Done Right: bcrypt, Argon2id and What Never to Use

Two rules carry most of password security. First, length beats complexity: four random words are far stronger than an eight-character scramble, and easier to type. Aim for at least 12–16 characters. Second, uniqueness per service: a leak at one site must not unlock your mailbox and your bank. A password manager makes both rules easy — it remembers long unique strings so you do not have to.

On the server: slow and salted or nothing

User passwords must be stored as hashes designed to be slow, with a unique salt baked in. The current recommendations:

  • Argon2id: the winner of the Password Hashing Competition; tunable in memory, time and parallelism, which makes GPU cracking expensive.
  • bcrypt: battle-tested for two decades, has a cost factor, and is still perfectly acceptable. Its 72-byte input limit is worth knowing when passphrases get long.
  • PBKDF2: slower to attack than raw SHA but weaker than the two above; acceptable only where regulation demands it.
  • Never MD5 or SHA-1, and never plain SHA-256: these are fast by design. Fast hashing is exactly what makes an offline crack cheap — modern GPUs test billions of SHA-1 candidates per second.

In PHP, the built-in function picks a sane default and handles salting for you:

// store
password_hash("correct horse battery staple", PASSWORD_DEFAULT);
// verify
if (password_verify("candidate", stored_hash)) { /* login */ }

PASSWORD_DEFAULT is bcrypt today and can move to stronger algorithms in future releases, and password_needs_rehash() lets you upgrade old hashes transparently at login. Never invent your own scheme, never add a "secret pepper" as a substitute for a proper algorithm, and never truncate input before hashing.

Passphrases and the human side

The most durable password advice is to stop inventing passwords one character at a time. A passphrase built from four or five random words — chosen by dice or a generator, not by taste — delivers 50+ bits of entropy and can be memorised. Human-chosen "complex" passwords cluster around predictable patterns (capital first, digit and symbol last), which cracking rules exploit first. If a site caps length at something silly like 12 characters, that cap is itself a signal about how the site handles passwords.

Beyond the pair of rules above: turn on two-factor authentication wherever it exists, since it survives a leaked password; check whether your addresses appear in breach dumps and change those passwords immediately; and never rotate strong unique passwords on a schedule — forced 90-day rotation makes people pick weaker passwords, which is why modern guidance (NIST SP 800-63) dropped it.

Generating secrets correctly

Any value that acts as a credential — reset tokens, API tokens, share links — must come from a cryptographically secure random source, not from rand() or uniqid(), and must be long enough that guessing is hopeless: 128 bits of entropy is a good floor. In PHP that means random_bytes(32), base64-encoded for transport. The same generator should back your password generator.

Strength on the user side and slow hashing on the server side only work as a pair: a great password stored under MD5 is still weak, and bcrypt cannot rescue "123456". When you need a fresh passphrase or token, use the WhoDNS password generator — it draws from the secure system random source, runs entirely server-side, and never stores what it produces.

🔗 Related tool: Generate a strong random password

password hashingbcryptargon2idpassword_hashpassword manager