TL;DR
Implementing a secure password reset feature requires careful attention to detail. This guide outlines best practices for generating tokens, handling email delivery, validating input, and securely updating passwords. Focus on preventing common attacks like brute-force attempts and token hijacking.
1. Token Generation & Storage
- Generate a Unique Token: Use a cryptographically secure random number generator to create a unique token for each password reset request. Avoid predictable patterns.
- Token Length: Tokens should be sufficiently long (at least 32 characters) to make brute-force attacks impractical.
- Storage: Store the token along with the associated user ID and an expiration timestamp in a secure database. Never store passwords directly!
- Example (Python):
import secrets import datetime def generate_token(): return secrets.token_urlsafe(32) def store_token(user_id, token): # Store user_id, token, and expiration timestamp in your database. pass # Replace with actual database interaction
2. Email Delivery
- Secure Connection: Use TLS/SSL to encrypt email communication (e.g., SMTPs).
- Unique Reset Link: Include a link in the email containing the token and user ID. This link should point to a dedicated password reset page on your application.
- Expiration Time: Clearly state the expiration time of the reset link in the email (e.g., “This link will expire in 1 hour”).
- Avoid Sensitive Information: Do not include any sensitive user information directly in the email body or subject line.
3. Password Reset Page
- Token Validation: When a user clicks the reset link, validate the token against your database.
- Check if the token exists.
- Verify that the token has not expired.
- Ensure the token is associated with the correct user ID.
- Input Validation: Implement robust input validation on the new password fields.
- Minimum length requirements (e.g., 8 characters).
- Complexity requirements (e.g., uppercase, lowercase, numbers, symbols).
- Prevent common passwords and patterns.
- Hashing: Hash the new password using a strong hashing algorithm (e.g., bcrypt, Argon2) *before* storing it in the database.
import bcrypt def hash_password(password): hashed = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt()) return hashed.decode('utf-8') - Token Revocation: Once the password is successfully reset, invalidate the token in your database to prevent reuse.
4. Security Considerations
- Rate Limiting: Implement rate limiting on password reset requests to prevent brute-force attacks. Limit the number of requests from a single IP address or user account within a specific timeframe.
- Account Lockout: Consider locking accounts after multiple failed password reset attempts.
- HTTPS: Ensure your entire application is served over HTTPS to protect against man-in-the-middle attacks.
- Cross-Site Request Forgery (CSRF) Protection: Protect the password reset form with CSRF tokens.
- Regular Security Audits: Conduct regular security audits and penetration testing to identify and address potential vulnerabilities in your password reset implementation.
5. References
- OWASP Password Reset Credential Stuffing Prevention Cheat Sheet: https://owasp.org/www-project-password-reset-credential-stuffing-prevention-cheat-sheet
- OWASP Authentication Cheat Sheet: https://owasp.org/www-project-authentication-cheat-sheet