繁体   English   中英

如何减少 Asp.Net Identity 中的密码重置令牌长度?

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

我正在使用 Asp.Net Identity 来生成密码重置令牌。

string Token = userManager.GeneratePasswordResetToken(userId);

上面的代码给了我一个大长度的令牌。 是否可以生成长度较短的密码重置令牌?

您可以使用TotpSecurityStampBasedTokenProvider生成 6 位数字:

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

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

并在启动类中添加:

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

您的密码重置令牌需要是加密随机的——这意味着给定一组使用过的令牌,下一个令牌应该是不可能猜到的。 它还需要覆盖足够大的一组可能值,以致尝试所有这些值的蛮力速度非常慢。

您可以进行更改以使后者使用较小的可能值集 - 例如,您可以在检查令牌之前向密码重置页面/操作添加 1 秒延迟。 您的用户几乎不会注意到很少使用的页面上的延迟,但攻击者将无法快速尝试大量令牌。

所以,首先你需要得到一个加密随机数:

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

我在这里放了8个字节,但您可以将其设置为任何您想要的长度。

接下来你需要把它变成一个很好的可复制粘贴的字符串。 您可以使用 unicode 转换来做到这一点,但我发现 base 64 更可靠:

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

将它与8个字节一起使用将为您提供 64 位的可能值和一个 10 个字符的字符串。 使用4将为您提供 32 位(可能足以在低安全性站点上进行慢速令牌检查)和 5 个字符的字符串。

我有一个理想的解决方案,建立在此处找到的体面答案的基础上。 首先,您必须在相关类中注入IMemoryCache

public class ResetController : ControllerBase
{
    private readonly IMemoryCache _memoryCache;
    public ResetController(IMemoryCache memoryCache)
    {
        _memoryCache = memoryCache;
    }
}

其次,内存缓存允许您创建存储在缓存中的键值对关系,以便稍后可以使用键检索值。 在这种情况下,值是实际生成的令牌,键是变量truncatedtoken

var token = await _userManager.GeneratePasswordResetTokenAsync(user);
string tokentruncated;

using (RandomNumberGenerator rng = new RNGCryptoServiceProvider())
{
    byte[] tokenData = new byte[32];
    rng.GetBytes(tokenData);
    tokentruncated = Convert.ToBase64String(tokenData);
}

var cacheEntryOptions = new MemoryCacheEntryOptions()
                    .SetSlidingExpiration(TimeSpan.FromDays(1));
_memoryCache.Set(tokentrunc, token, cacheEntryOptions);

发送确认令牌 ( truncatedtoken ) 并且用户准备好重置密码后。 truncatedtoken密钥用于检索实际令牌。

string token;
_memoryCache.TryGetValue(truncatedtoken, out token);
 var result = await _userManager.ResetPasswordAsync(user, token, "New password");

除了使用TryGetValue ,您还可以使用以下方法检索令牌;

string token = _memoryCache.Get<string>(truncatedtoken);

用较短的代码替换长代码并存储在应用程序缓存中。

生成时:

var token = UserManager.GeneratePasswordResetToken(user.Id);
var guidCode = GenerateCustomToken(); //use this https://stackoverflow.com/a/1668371/631527
CacheHelper.AddToCache(guid, token); //add it to MemoryCache.Default
var resetUrl = $"https://.....com/password-reset/{guidCode}/{userName}";

检查时:

//get guidCode from the request in your GET or POST controller
var token = CacheHelper.GetValue(guidCode); //retrieve it from cache
var result = UserManager.ResetPassword(user.Id, token, model.Password);

一件事是生成您自己的 8 位 GUID 并将其发送给用户并拥有自己的查找表以获取真实令牌。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM