← Back to Blog
Security 15 min read

Password Security Best Practices: Complete Developer Guide

Learn modern password security practices, hashing algorithms, storage strategies, and implementation guidelines for building secure authentication systems.

Introduction to Password Security

Password security is fundamental to application security. Despite advances in authentication methods like OAuth and biometrics, passwords remain the most common authentication mechanism. This guide covers modern best practices for password handling, storage, and validation.

Warning: Never store passwords in plain text. Always use appropriate hashing algorithms with salt and appropriate work factors.

Modern Password Requirements

Traditional password policies often create poor user experiences without improving security. Modern approaches focus on length and complexity rather than arbitrary character requirements.

Recommended Requirements

  • Minimum length: 12 characters (preferably 16+)
  • Maximum length: 128 characters (allow long passphrases)
  • Character sets: Allow all Unicode characters
  • No complexity rules: Don't require specific character types
  • Common password checks: Check against known breached passwords

What to Avoid

  • Password expiration policies (NIST no longer recommends)
  • Maximum password age requirements
  • Arbitrary complexity rules (must include number, symbol, etc.)
  • Password hints that reveal the password

Password Hashing Algorithms

Choosing the right hashing algorithm is critical for password security. Here are the recommended algorithms in order of preference:

1. Argon2 (Recommended)

Winner of the Password Hashing Competition (PHC), Argon2 is memory-hard and resistant to GPU/ASIC attacks.

// Example: Argon2 implementation in Node.js const argon2 = require('argon2'); async function hashPassword(password) { return await argon2.hash(password, { type: argon2.argon2id, memoryCost: 65536, // 64MB timeCost: 3, parallelism: 4 }); } async function verifyPassword(hash, password) { return await argon2.verify(hash, password); }

2. bcrypt

Well-established, battle-tested algorithm with built-in salt and adjustable work factor.

// Example: bcrypt implementation const bcrypt = require('bcrypt'); const saltRounds = 12; // Adjust based on your security needs async function hashPassword(password) { return await bcrypt.hash(password, saltRounds); } async function verifyPassword(hash, password) { return await bcrypt.compare(password, hash); }

3. scrypt

Memory-hard algorithm designed to be resistant to hardware attacks.

Password Storage Strategies

Database Schema Design

CREATE TABLE users ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), email VARCHAR(255) UNIQUE NOT NULL, password_hash VARCHAR(255) NOT NULL, salt VARCHAR(255) NOT NULL, -- If not using built-in salt algorithm VARCHAR(50) NOT NULL DEFAULT 'argon2id', work_factor INTEGER NOT NULL DEFAULT 3, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, last_password_change TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); -- Add indexes for performance CREATE INDEX idx_users_email ON users(email); CREATE INDEX idx_users_created_at ON users(created_at);

Security Considerations

  • Separate authentication database: Store password hashes separately from user data
  • Encrypt at rest: Use database encryption for sensitive columns
  • Audit logging: Log authentication attempts (success/failure)
  • Rate limiting: Implement login attempt limits

Implementation Guidelines

Registration Flow

  1. Validate password meets requirements
  2. Check against known breached passwords (HaveIBeenPwned API)
  3. Generate cryptographically secure salt
  4. Hash password with appropriate algorithm
  5. Store hash and metadata in database
  6. Send confirmation email (if required)

Login Flow

  1. Retrieve user record by email/username
  2. Verify password hash matches
  3. Update last login timestamp
  4. Generate session token/JWT
  5. Set secure HTTP-only cookie
Tip: Use constant-time comparison for password verification to prevent timing attacks.

Common Password Security Vulnerabilities

1. Weak Hashing Algorithms

Avoid: MD5, SHA-1, SHA-256 (without proper key stretching)

These algorithms are too fast and vulnerable to brute force attacks.

2. Insufficient Work Factor

bcrypt with cost factor less than 12 or Argon2 with insufficient memory/time cost.

3. No Salt or Weak Salt

Using the same salt for all passwords or insufficiently random salt.

4. Password in Logs

Accidentally logging passwords in application logs or error messages.

Tools and Resources

DailyTools.uk Password Tool

Use our Password Generator Tool to create secure passwords and test password strength.

External Resources

Conclusion

Password security requires careful implementation of modern best practices. Focus on using strong hashing algorithms (Argon2, bcrypt), appropriate work factors, and comprehensive validation. Regularly audit your password handling code and stay updated with security recommendations from organizations like OWASP and NIST.

Remember that password security is just one component of a comprehensive authentication system. Consider implementing multi-factor authentication (MFA), monitoring for suspicious activity, and providing users with password managers to improve overall security.