Hash, Salt, and Your Security: Why It Matters in 2025?
\n\nImagine: you've built a cool website, everything works, users are registering. But one day the database leaks online. What will attackers see? If you store passwords in plain text — it's a disaster. If you use old md5 — it's almost the same. But if you applied secure hash and salt — attackers will only see a meaningless set of characters. In 2025, this is not just a recommendation, but a security standard.
\n\nIn this article, we'll break down how to properly hash passwords in PHP using modern algorithms, salt, and best practices. You'll learn why old methods are dangerous and how to switch to secure password storage in 10 minutes.
\n\nWhy md5 and sha1 are Evil?
\n\nMany beginner developers make the same mistake: using md5($password) or sha1($password). In 2025, this is not just bad practice, but a direct path to vulnerability. Why?
- \n
- Computation speed. MD5 and SHA1 were designed for speed, not security. Modern GPUs can brute-force billions of hashes per second. \n
- Lack of salt. If two users choose the same password, their hashes will be identical. This allows the use of rainbow tables. \n
- Collisions. Practical collisions have been found for MD5 — two different inputs produce the same hash. \n
Fortunately, PHP has built-in functions that solve all these problems. And this doesn't require installing third-party libraries.
\n\npassword_hash and password_verify: Your Secret Weapon
\n\nStarting from PHP 5.5.0, two magical functions appeared in the language: password_hash() and password_verify(). They automatically generate a salt, use cryptographically strong algorithms, and protect against timing attacks.
Example of simplest usage:
\n\n// Hashing a password\n$password = "MySuperSecureP@ssw0rd!";\n$hash = password_hash($password, PASSWORD_DEFAULT);\necho $hash; // $2y$10$...\n\n\nWhat happened here? The password_hash function:
- \n
- Generated a random salt \n
- Selected the optimal algorithm (bcrypt by default) \n
- Computed the hash \n
- Returned a string that contains the hash, salt, and algorithm information \n
Verifying a password looks just as simple:
\n\n// Verifying a password\n$inputPassword = "MySuperSecureP@ssw0rd!";\nif (password_verify($inputPassword, $hash)) {\n echo "Password is correct!";\n} else {\n echo "Password is incorrect.";\n}\n\n\nNote: you don't need to store the salt separately. It is already embedded in the hash. This is secure hash and salt in action.
\n\nWhich Algorithm to Choose in 2025?
\n\nBy default, password_hash uses bcrypt. This is an excellent choice for most projects. But we have other options:
| Algorithm | \nConstant | \nRecommendation | \n
|---|---|---|
| Bcrypt | \nPASSWORD_BCRYPT | \n Excellent choice, supported everywhere | \n
| Argon2i | \nPASSWORD_ARGON2I | \n Resistant to side-channel attacks | \n
| Argon2id | \nPASSWORD_ARGON2ID | \n Best choice in 2025 | \n
Argon2id is the winner of the PHC (Password Hashing Competition). It is resistant to both GPU attacks and timing attacks. If your PHP is compiled with Argon2 support (and in PHP 8.x it's already standard), use it.
\n\nConfiguring Hashing Cost
\n\nOne of the key ideas of secure hash and salt is to make the comp