Skip to content

Upgraded PasswordHasher in net 7 causes a security stamp update to occur, which logs users out after 30 minutes #46185

@lbargery

Description

@lbargery

Is there an existing issue for this?

  • I have searched the existing issues

Describe the bug

Apologies if I've missed something here, or this is in fact intended behaviour.

We upgraded all our servers to Net core 7 this week. When we released our "account" server which handles login etc we started noticing low levels of 401s occurring for some users. We initially upgraded the log level to Debug and found that the 401 was due to a security stamp mismatch between claims principal and the database. It seemed like the security stamp had somehow changed under the user. To verify this, we took a database snapshot from 2 days ago and did find the stamp had changed.

We rolled back to net 6.0 and the 401s went away. Digging through the flow on UserManager.cs for what happens when a user logs in, I found this code in CheckPasswordAsync:

ThrowIfDisposed();
var passwordStore = GetPasswordStore();
if (user == null)
{
    return false;
}

var result = await VerifyPasswordAsync(passwordStore, user, password).ConfigureAwait(false);
if (result == PasswordVerificationResult.SuccessRehashNeeded)
{
    await UpdatePasswordHash(passwordStore, user, password, validatePassword: false).ConfigureAwait(false);
    await UpdateUserAsync(user).ConfigureAwait(false);
}

var success = result != PasswordVerificationResult.Failed;
if (!success)
{
    Logger.LogDebug(LoggerEventIds.InvalidPassword, "Invalid password for user.");
}
return success;

Upon further investigation, it seemed like the default iteration count had gone from 10k to 100k and algorithm from SHA256 to SHA512 when upgrading from net 6 to net 7. I believe this means that over time, all our users will experience a rehash.

The issue is that when the code above runs, it not only rehashes the password but it also updates the security stamp (as is the impl of UpdatePasswordHash). This is okay for the actual caller here but if we imagine we have a user logged into two devices the second device will now be logged out after 30 minutes since it hasn't seen the update to the security stamp.

Expected Behavior

I would expect the password to be re-hashed, but no security stamp change on this particular call otherwise a user just logging in on one device has the consequence that it logs them out on every other device.

Steps To Reproduce

  • Clone the following repo https://github.com/lbargery/netcore-secstamp-bug
  • Run the application, create a user account with any email and hit "confirm" in the UI
  • Open a private/an incognito browser and log in with the same account you created above
  • Navigate to "https://localhost:7042/Home/LoggedIn" which should be blank for both browsers
  • Keep the browsers open but end the application
  • Uncomment lines 19-22 in Program.cs which changes the Iteration count for the algorithm
  • In the normal browser (not private session), log out and log back in again and again navigate to "https://localhost:7042/Home/LoggedIn"
  • Wait 1 minute (this is the configured SecurityStampValidatorOptions validation interval)
  • Refresh normal browser -> still logged in
  • Refresh private browser -> now logged out

Exceptions (if any)

No response

.NET Version

7.0.2

Anything else?

No response

Metadata

Metadata

Assignees

Labels

DocsThis issue tracks updating documentationarea-identityIncludes: Identity and providersmigrationIndicates that the associated issue is related to migration from older version of the frameworkpending-ci-rerunWhen assigned to a PR indicates that the CI checks should be rerun

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions