Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to reduce password reset token length in Asp.Net Identity?

I am using Asp.Net Identity for generate a password reset token.

string Token = userManager.GeneratePasswordResetToken(userId);

above code is giving me a token with large length. Is it possible to generate password reset token with short length?

like image 937
sridharnetha Avatar asked Jun 29 '15 04:06

sridharnetha


2 Answers

You can use TotpSecurityStampBasedTokenProvider to generate 6-digit number:

public class ResetPasswordTokenProvider : TotpSecurityStampBasedTokenProvider<OriIdentityUser>
{
    public const string ProviderKey = "ResetPassword";

    public override Task<bool> CanGenerateTwoFactorTokenAsync(UserManager<OriIdentityUser> manager, OriIdentityUser user)
    {
        return Task.FromResult(false);
    }
}

And in the startup class add:

services.AddIdentity<IdentityUser, IdentityRole>(options =>
    {
        options.Tokens.PasswordResetTokenProvider = ResetPasswordTokenProvider.ProviderKey;
    })
    .AddDefaultTokenProviders()
    .AddTokenProvider<ResetPasswordTokenProvider>(ResetPasswordTokenProvider.ProviderKey);

like image 199
Pecan Avatar answered Oct 20 '22 01:10

Pecan


Your password reset token needs to be cryptographically random - that means that given a set of used tokens the next token should be impossible to guess. It also needs to cover a large enough set of possible values that brute force attempting all of them is impractically slow.

You can make changes to make the latter work with smaller sets of possible values - for instance you can add a 1s delay to the password reset page/action before checking the token. Your users will barely notice the delay on the rarely used page, but attackers will not be able to attempt lots of tokens quickly.

So, first you need to get a cryptographically random number:

var random = new byte[8];
using (var rng = System.Security.Cryptography.RandomNumberGenerator.Create())
    rng.GetBytes(random);

I've put 8 bytes here but you can make this any length you want.

Next you need to make this into a nice copy-pasteable string. You can do that with a unicode conversion but I find base 64 more reliable:

Convert.ToBase64String(random).TrimEnd('=');

Using this with 8 bytes will give you 64 bits of possible values and a 10 char string. Using 4 will give you 32 bits (probably enough with slow token checking on a low security site) and a 5 char string.

like image 1
Keith Avatar answered Oct 20 '22 01:10

Keith