Description
A fixed salt in password hashing or key derivation makes identical inputs produce identical results under the same algorithm and settings. An attacker can reuse the computation for a password candidate across multiple users.
Potential impact
- Lower cost for dictionary attacks.
- Easier identification of users with the same password.
- Greater chance of recovering passwords from stolen hashes.
Remediation
- Generate a cryptographically secure random salt for each user/password.
- Store the salt with the hash if needed, but do not fix it as a constant in code.
- Use the salt-generation API of a reviewed password-hashing library. Choose an appropriate algorithm and work factor as well; a salt does not replace those controls.
Examples
Before
swift
try PKCS5.PBKDF2(
password: password,
salt: Array<UInt8>("staticSalt".utf8),
iterations: 600000,
keyLength: 32).calculate()
After
swift
import CryptoSwift
func derivePasswordKey(
password: [UInt8]
) throws -> (salt: [UInt8], derivedKey: [UInt8]) {
let salt = (0..<16).map { _ in UInt8.random(in: 0...UInt8.max) }
let derivedKey = try PKCS5.PBKDF2(
password: password, salt: salt, iterations: 600000, keyLength: 32
).calculate()
return (salt, derivedKey)
}
Explanation:
- Before: Sharing a salt across users lets an attacker reuse previously computed password candidates.
- After: Each hash uses a new random salt. Store it with the derived key so it is available for later verification.