If you run a website you do more than host content , you also protect people’s accounts and data. Passwords are often the weakest link attackers try to exploit, so understanding how to store, validate, and manage them is essential. This guide walks through practical steps you can take today, why they matter, and how to avoid common mistakes that lead to account takeovers and data breaches.
Why password handling matters
Users reuse passwords, phishers trick people, and automated attacks try millions of guesses per minute. If you store passwords incorrectly or implement weak reset flows, one breach can expose thousands of accounts. Secure password practices reduce the damage from credential leaks, slow attackers so detection is possible, and protect user trust , which is often far more valuable than short-term convenience when you choose lax defaults.
Store passwords securely: hashing, salts, and modern algorithms
Never store plaintext passwords. Instead, use a purpose-built password hashing algorithm that is intentionally slow and memory-hard to resist brute-force and GPU attacks. Recommended choices today are Argon2id and bcrypt. When a user sets a password, create a unique salt for that password, combine it with the password, and run it through the hashing function. Store only the salt and the resulting hash in your database.
Key rules for hashing
- Use one strong, per-password salt stored alongside the hash; do not reuse salts across users.
- Pick a modern algorithm: Argon2id is preferred where available; bcrypt is still acceptable when configured with a high cost parameter.
- Tune work factors over time: increase cost as hardware improves, and re-hash passwords on next successful login if the stored hash uses an older cost.
- Avoid raw cryptographic hashes like SHA-256 or MD5 for password storage , they’re fast and easy for attackers to brute-force.
- Consider a pepper (a secret stored separately from the database) only with careful operational controls; if mismanaged it can complicate recovery.
Password policies that balance security and user experience
Rigid complexity rules (forcing symbols, numbers, and mixed case) often lead users to predictable patterns and password reuse. Instead, focus on length and entropy: require a reasonable minimum length (at least 12 characters for user-created passwords) and encourage passphrases of several random words. Use client-side strength meters like zxcvbn to give helpful feedback, and block the most common or compromised passwords using lists from breach data.
Good policy checklist
- Minimum length: 12 characters for user-created passwords; 8 acceptable temporarily for device-constrained flows but combined with strong additional controls.
- Blacklist known-bad passwords and leaked credentials (use services such as Have I Been Pwned or similar APIs).
- Avoid frequent forced resets , require them only after evidence of compromise or when there’s a real risk. Forced periodic resets can lower security.
- Allow and encourage password managers and passphrases; they improve both security and usability.
Defend login flows and rate limits
Brute-force and credential stuffing attacks are automated. Throttle attempts, implement exponential backoff, and block suspicious IP addresses or fingerprinted clients. Rather than permanently locking accounts after a few failed attempts, consider progressive delays and step-up verification such as CAPTCHA or email/SMS verification for further attempts. Log failed attempts and alert on unusual patterns so you can detect credential stuffing campaigns early.
Multi-factor authentication: the most effective extra layer
Multi-factor authentication (MFA) dramatically reduces account takeovers even when passwords are compromised. Offer time-based one-time passwords (TOTP) and security keys (WebAuthn) as primary options. SMS can help some users but is vulnerable to SIM swapping and should not be relied on as the only second factor. Make MFA enrollment straightforward and offer backup codes stored securely. Also allow a secure recovery path that doesn’t negate the benefits MFA provides.
Design a secure password reset flow
Password reset is a frequent attack target. Use short-lived, single-use tokens delivered over secure channels (usually email). Tokens should be long, random, stored hashed in the database, and expire quickly (for example, 15–60 minutes). Verify the requestor’s email or additional factors before allowing a reset that affects account recovery options. Avoid disclosing whether an email address exists in your system , prefer responses like “If this email is registered, we sent a reset link” to reduce account enumeration risk.
Client and server best practices
Ensure all password traffic is protected by https. Set cookies containing session tokens with Secure, HttpOnly, and SameSite flags to limit client-side access and cross-site leaks. Use CSP and other headers to reduce XSS risk, because cross-site scripting can expose session tokens and other sensitive flows. Store secrets and pepper values outside code repositories in environment variables or a secrets manager, and rotate secrets responsibly. On the server, re-hash passwords when upgrading hashing parameters and monitor authentication-related logs for anomalies.
User guidance and password managers
Encourage users to use password managers and provide clear education: unique passwords per site, enable MFA, watch for phishing attempts, and update passwords only when necessary. Provide a page in your help center explaining how to use authenticators, export recovery codes, and recognize legitimate emails from your service. Many users want to do the right thing when given practical options and tools rather than complex rules they can’t follow.
Monitoring, detection, and incident response
Plan for the possibility of compromise. Monitor for spikes in failed logins, unusual IP addresses, or credential stuffing. Subscribe to leaked credential feeds and run periodic checks against your user base (with user consent) to identify exposed credentials. If you detect a breach, force resets where appropriate, revoke active sessions, communicate clearly to affected users, and require MFA enrollment as part of remediation when feasible.
Practical implementation example (high level)
A simple secure flow for new accounts: receive password over HTTPS, generate a per-account salt, hash with Argon2id and a strong cost, store the salt and hash only, require email verification, offer MFA enrollment during or after signup, and limit login attempts with progressive delays. On password reset, send a short-lived, single-use token via email, verify it against a hashed token stored on the server, and prompt for a new password that meets your length/entropy policy. Re-hash existing hashes at login if you detect an older algorithm or weaker cost parameter.
Common pitfalls to avoid
- Storing plaintext passwords or reversible encryption of passwords.
- Using fast hashing algorithms (SHA family) without key stretching or memory hardness.
- Relying solely on SMS-based MFA for high-risk accounts.
- Giving detailed error messages that enable account enumeration or indicate which part of the login failed.
- Not rotating secrets or allowing stale hashing parameters to remain indefinitely.
