Choosing a hashing algorithm: MD5 vs SHA-1 vs SHA-256 vs bcrypt
"Just hash it" is not one recommendation — it is at least three, depending on what you are protecting against.
Fast hashes: MD5, SHA-1, SHA-256
MD5, SHA-1 and SHA-256 are all designed to be fast, which is exactly right for checking file integrity or generating a fingerprint of some content, and exactly wrong for storing passwords.
- **MD5** — 128-bit output, broken for collision resistance since 2004. Fine for detecting accidental corruption (comparing a downloaded file's checksum), unacceptable for anything security-sensitive.
- **SHA-1** — 160-bit output, practical collision attacks demonstrated in 2017 (the SHAttered attack). Still shows up in legacy Git internals and old certificates, but should not be chosen for anything new.
- **SHA-256** — part of the SHA-2 family, no known practical collision attack. The default choice for checksums, HMAC, certificate fingerprints, and blockchain-style content addressing.
Why fast is a problem for passwords
A modern GPU can compute billions of SHA-256 hashes per second. If a database of SHA-256(password) values leaks, an attacker can brute-force short or common passwords in minutes using rainbow tables or straightforward dictionary attacks with GPU acceleration. Speed is the attacker's friend here, not yours.
Slow, salted hashes for passwords
Password hashing functions are deliberately slow and configurable:
- **bcrypt** — mature, widely supported, has a built-in cost factor and salt. A safe default when you cannot use anything newer.
- **scrypt** — memory-hard, meaning it resists GPU/ASIC acceleration better than bcrypt by requiring significant RAM per hash.
- **Argon2** — winner of the 2015 Password Hashing Competition, memory-hard and tunable across time, memory and parallelism. The current best-practice recommendation for new systems (Argon2id variant).
None of these are available as a one-line Web Crypto API call — they require a dedicated library, which is why "hash the password with SHA-256 in JavaScript" is a recurring anti-pattern in tutorials.
Salting matters regardless
A salt is random data mixed into the input before hashing, unique per record. It defeats precomputed rainbow tables and ensures two users with the same password get different hashes. bcrypt, scrypt and Argon2 all generate and store the salt as part of their output format automatically — you do not manage it separately.
HMAC: hashing with a key
HMAC combines a hash function with a secret key, producing a value that proves both integrity and authenticity — an attacker without the key cannot forge a valid HMAC even if they know the algorithm. It is the mechanism behind JWT's HS256 signatures, webhook signature verification (Stripe, GitHub), and API request signing.
HMAC-SHA256(key, message) = a fixed-length authenticated tagQuick decision guide
- Checking a downloaded file against a published checksum → SHA-256.
- Deduplicating content or generating a stable ID from data → SHA-256.
- Verifying a webhook payload → HMAC-SHA256 with the provider's shared secret.
- Storing user passwords → bcrypt or Argon2, never a plain fast hash.
- Anything currently using MD5 or SHA-1 for security purposes → migrate it.