Implementation Best Practices
Implementation Best Practices
Successful deployment of modern password hashers requires more than selecting an algorithm. Parameter selection must balance security with performance constraints. Web applications typically target 50-100ms for password hashing to maintain responsive user experience. High-security applications might tolerate 500ms or more. Background services can use even higher parameters since user interaction isn't immediate.
Error handling deserves special attention. Password hashing can fail due to memory allocation issues (especially with scrypt/Argon2), invalid parameters, or corrupted stored hashes. Implement graceful degradation that maintains security—never fall back to weaker algorithms on failure. Log failures for monitoring while avoiding information leakage that could aid attackers.
class SecurePasswordManager:
"""Example implementation with proper error handling and migration support"""
def __init__(self):
self.ph = PasswordHasher(
time_cost=3,
memory_cost=65536,
parallelism=4,
type=Type.ID
)
def hash_password(self, password):
"""Hash password with comprehensive error handling"""
try:
if not password or len(password) < 8:
raise ValueError("Password too short")
if len(password) > 128: # Prevent DoS
raise ValueError("Password too long")
return self.ph.hash(password)
except MemoryError:
# Log error securely
self._log_error("Memory allocation failed during hashing")
raise SystemError("System temporarily unavailable")
except Exception as e:
# Don't leak information about the error
self._log_error(f"Hashing failed: {type(e).__name__}")
raise SystemError("Password processing failed")
def verify_password(self, password, hash_str):
"""Verify password with timing attack protection"""
try:
self.ph.verify(hash_str, password)
# Check if rehashing needed
if self.ph.check_needs_rehash(hash_str):
return True, self.hash_password(password)
return True, None
except argon2.exceptions.VerifyMismatchError:
# Ensure constant time on failure
time.sleep(0.001) # Minimal delay to prevent timing attacks
return False, None
except Exception:
self._log_error("Verification error")
return False, None
def _log_error(self, message):
"""Secure error logging"""
# Log without sensitive information
print(f"[SECURITY] {message}")
# Usage example
pm = SecurePasswordManager()
hashed = pm.hash_password("MySecurePassword123!")
valid, new_hash = pm.verify_password("MySecurePassword123!", hashed)
print(f"Password valid: {valid}")
if new_hash:
print("Password rehashed with updated parameters")