Course contentsShow
← C#
Lesson 1182 of 1,90811. Identity, Security, and ClaimsFree lesson

Securing Account Recovery Workflows

Design secure password reset flows that avoid common vulnerabilities like token leakage.

In this lesson, you will learn how to design secure password reset flows that prevent token leakage and common account takeover vulnerabilities.

When a user forgets their password, your system typically generates a unique, time-sensitive token sent via email. The core security challenge is ensuring this token cannot be intercepted, reused, or brute-forced.

1. Token Generation and Storage

Never use simple incrementing IDs or predictable strings for password resets. Use a cryptographically secure random number generator (like RNGCryptoServiceProvider or RandomNumberGenerator) to create a high-entropy token.

Crucially, do not store the plain-text token in your database. Just like passwords, you should store a salted hash of the token. When the user clicks the link in their email, you hash the incoming token and compare it against the stored hash.

2. Preventing Leakage

Tokens should never appear in server logs, URL referer headers, or browser history.

  • Avoid GET requests for state-changing actions: While the initial "reset" link must be a GET (to load the form), ensure the actual password submission happens via a POST request.
  • Use Referrer-Policy: Set headers to no-referrer to ensure the sensitive token isn't leaked to third-party scripts if the user navigates away from your site.

3. Implementation Logic

Here is a simplified approach to verifying a reset token:

public async Task<bool> ValidateResetTokenAsync(string userId, string providedToken)
{
    var storedHash = await _context.UserTokens
        .Where(t => t.UserId == userId && t.Purpose == "Reset")
        .Select(t => t.Hash)
        .FirstOrDefaultAsync();

    // Use a constant-time comparison to prevent timing attacks
    return HashHelper.VerifyHash(providedToken, storedHash);
}

4. Security Hardening

  • Immediate Expiration: Ensure tokens expire after a very short window (e.g., 15–30 minutes).
  • Single Use: Once a token is used to successfully change a password, immediately invalidate all other outstanding reset tokens for that user.
  • Rate Limiting: Protect your reset endpoint from brute-force attempts by limiting the number of reset requests allowed per email address in a given hour.

Key Takeaway: Always store password reset tokens as salted hashes, implement strict short-lived expiration policies, and ensure the actual password update process occurs over a secure POST request.