# Laravel Weak Password Hashing: How to Replace md5 and sha1 with bcrypt

> Using md5() or sha1() for password hashing is trivially crackable. Laravel uses bcrypt by default — make sure your application does too.

**Severity:** high | **Category:** Application Security

---

## The Issue

MD5 and SHA-1 are fast hash functions designed for data integrity, not password storage. Modern GPUs can compute billions of MD5 hashes per second, making brute-force attacks trivial. A database of MD5-hashed passwords can be cracked in minutes using rainbow tables. Laravel uses bcrypt (or argon2) by default through Hash::make(), but legacy code or custom authentication may bypass this. Any password hashed with md5() or sha1() should be considered compromised.

## Steps to Fix

### 1. Find all weak hashing in your codebase

Search for md5 and sha1 used in authentication or password contexts:

grep -rn 'md5(\|sha1(' app/ --include='*.php'

Look specifically for:
- md5($password) or sha1($password)
- Custom authentication that compares md5 hashes
- Legacy database columns with 32-character (md5) or 40-character (sha1) hashes

Note: md5() used for cache keys, ETags, or non-security purposes is acceptable.

### 2. Replace with Hash::make() and Hash::check()

Use Laravel's built-in hashing:

use Illuminate\Support\Facades\Hash;

// Hashing a password
$hashed = Hash::make($password);

// Verifying a password
if (Hash::check($plaintext, $hashed)) {
    // Password matches
}

// In a User model / registration
User::create([
    'password' => Hash::make($request->password),
]);

Laravel's Hash facade uses bcrypt by default with automatic salt generation. You can configure the algorithm in config/hashing.php.

### 3. Migrate existing md5/sha1 passwords

For existing users with legacy hashes, rehash on login:

// In your LoginController or custom auth logic
if ($user && md5($password) === $user->password) {
    // Legacy hash matches — rehash with bcrypt
    $user->update([
        'password' => Hash::make($password),
    ]);
    Auth::login($user);
}

After a reasonable migration period, force remaining users to reset their passwords.

## Verification

Check your database for short hash values (md5 = 32 chars, sha1 = 40 chars, bcrypt = 60 chars):

SELECT id, LENGTH(password) as hash_length FROM users WHERE LENGTH(password) < 60;

Any results indicate weak hashing. Run php artisan stackshield:scan --check=SS042 to scan for md5/sha1 usage in code.

## Prevention

Never use md5() or sha1() for passwords. Always use Hash::make(). Configure bcrypt rounds in config/hashing.php (default 12 is good). Consider upgrading to argon2id for new applications. Use StackShield to scan for weak hashing patterns.

---

## Frequently Asked Questions

### Is sha256 safe for password hashing?

No. SHA-256 is faster than md5/sha1 but still a fast hash function. Password hashing requires intentionally slow algorithms like bcrypt, argon2, or scrypt that make brute-force attacks computationally expensive. Use Hash::make() which handles this correctly.

### What bcrypt rounds should I use?

Laravel defaults to 12 rounds, which takes about 250ms to hash. This is a good balance between security and performance. Increase to 13-14 if your server can handle it. You can set this in config/hashing.php or .env with BCRYPT_ROUNDS.

