Hashing Algorithms Deep Dive
debt(d5/e3/b3/t7)
Closest to 'specialist tool catches it' (d5), because detection_hints lists semgrep, psalm, and phpstan with a code_pattern targeting md5()/sha1() in security contexts. These are not default linters but specialist static analysis tools that must be configured to catch the pattern — the misuse won't surface from a basic syntax or default linter check.
Closest to 'simple parameterised fix' (e3), because the quick_fix is essentially a function-name swap (md5→SHA-256, SHA-1→BLAKE3, plain hash→Argon2id/HMAC-SHA256). Each individual misuse is a targeted replacement within a small number of call sites, but across an entire codebase multiple files may need touching, keeping it from being a pure e1 single-line patch.
Closest to 'localised tax' (b3), because the choice of hash function is typically scoped to specific subsystems (auth, file integrity, caching). It applies to web/cli/queue contexts but doesn't impose a cross-cutting gravitational pull on every future change — once corrected in the relevant component, the rest of the codebase is largely unaffected.
Closest to 'serious trap' (t7), because the misconception is a direct contradiction of developer intuition: 'faster is better' is correct in almost every other performance context, but for passwords slower is explicitly correct. This contradicts how performance optimization reasoning works elsewhere, and the common_mistakes show four distinct real-world failure modes (password hashing, checksum misuse, collision attacks, security forgery) — a competent developer new to the domain will almost certainly guess wrong.
Also Known As
TL;DR
Explanation
Hash functions serve different purposes: Cryptographic hashes (SHA-256, SHA-3, BLAKE3) — collision and pre-image resistant, for data integrity and HMACs. Password hashing (bcrypt, Argon2id, scrypt) — deliberately slow, memory-hard, salted. Non-cryptographic hashes (xxHash, MurmurHash, CRC32) — extremely fast, not collision-resistant, for hash tables and checksums where security is not required. MD5 and SHA-1 are broken (collision attacks demonstrated) — never use for security. PHP: hash() for cryptographic, password_hash() for passwords, crc32() for non-security checksums.
Common Misconception
Why It Matters
Common Mistakes
- SHA-256 or MD5 for passwords — fast algorithms, GPU-crackable at billions per second.
- bcrypt for non-security checksums — 400ms per hash where 1 microsecond is sufficient.
- MD5 for file integrity — collision attacks allow two different files with the same MD5.
- CRC32 for security applications — CRC32 is not cryptographic and easily forged.
Code Examples
// Wrong hash for the job:
$passwordHash = hash('sha256', $password); // GPU-crackable in seconds
$checksum = password_hash($data, PASSWORD_BCRYPT); // 400ms for a file checksum!
$fileInteg = md5_file($upload); // Collision-vulnerable integrity check
// Right hash for each use case:
// Passwords — slow, memory-hard:
$passwordHash = password_hash($password, PASSWORD_ARGON2ID);
// File integrity — cryptographic, collision-resistant:
$checksum = hash_file('sha256', $uploadPath);
// HMAC — authenticated integrity:
$mac = hash_hmac('sha256', $message, $secretKey);
// Cache key (non-security) — fast:
$cacheKey = 'page:' . crc32($url . $queryString); // Fast, not security
// Constant-time comparison for all security-sensitive comparisons:
if (!hash_equals($expected, $computed)) throw new SecurityException();