当我们网站上的用户丢失密码并转到丢失密码页面时,我们需要给他一个新的临时密码。我并不介意这有多随机,或者它是否符合所有“所需的”强密码规则,我想做的只是给他们一个他们以后可以更改的密码。

该应用程序是用c#编写的Web应用程序。所以我想刻薄一点,走一条简单的路线,用Guid的一部分。即。

Guid.NewGuid().ToString("d").Substring(1,8)

Suggesstions吗?想法吗?


当前回答

我喜欢生成密码,就像生成软件密钥一样。您应该从遵循良好实践的字符数组中进行选择。采用@Radu094回答的内容并修改它以遵循良好的实践。不要把每个字母都放在字符数组中。有些信在电话里更难读懂。

您还应该考虑对生成的密码使用校验和,以确保它是由您生成的。实现这一点的一个好方法是使用LUHN算法。

其他回答

我知道这是一个旧线程,但我有什么可能是一个相当简单的解决方案供某人使用。易于实现、易于理解、易于验证。

考虑以下要求:

我需要一个随机密码生成,其中至少有2个小写字母,2个大写字母和2个数字。密码长度至少为8个字符。

下面的正则表达式可以验证这种情况:

^(?=\b\w*[a-z].*[a-z]\w*\b)(?=\b\w*[A-Z].*[A-Z]\w*\b)(?=\b\w*[0-9].*[0-9]\w*\b)[a-zA-Z0-9]{8,}$

这超出了这个问题的范围——但是正则表达式是基于前向/后向和前后向的。

下面的代码将创建一个匹配这个要求的随机字符集:

public static string GeneratePassword(int lowercase, int uppercase, int numerics) {
    string lowers = "abcdefghijklmnopqrstuvwxyz";
    string uppers = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    string number = "0123456789";

    Random random = new Random();

    string generated = "!";
    for (int i = 1; i <= lowercase; i++)
        generated = generated.Insert(
            random.Next(generated.Length), 
            lowers[random.Next(lowers.Length - 1)].ToString()
        );

    for (int i = 1; i <= uppercase; i++)
        generated = generated.Insert(
            random.Next(generated.Length), 
            uppers[random.Next(uppers.Length - 1)].ToString()
        );

    for (int i = 1; i <= numerics; i++)
        generated = generated.Insert(
            random.Next(generated.Length), 
            number[random.Next(number.Length - 1)].ToString()
        );

    return generated.Replace("!", string.Empty);

}

要满足上述要求,只需调用以下命令:

String randomPassword = GeneratePassword(3, 3, 3);

代码以一个无效字符(“!”)开始——这样字符串就有一个长度,可以向其中注入新字符。

然后,它从1循环到所需的小写字符#,在每次迭代中,从小写列表中抓取一个随机项,并将其注入字符串中的随机位置。

然后对大写字母和数字重复循环。

这将返回长度=小写字母+大写字母+数字的字符串,其中您想要的计数的小写字母、大写字母和数字字符已按随机顺序放置。

我不喜欢Membership.GeneratePassword()创建的密码,因为它们太丑了,有太多特殊字符。

这段代码生成一个10位不太难看的密码。

string password = Guid.NewGuid().ToString("N").ToLower()
                      .Replace("1", "").Replace("o", "").Replace("0","")
                      .Substring(0,10);

当然,我可以使用一个Regex来做所有的替换,但这是更具可读性和可维护性的IMO。

我创建的这个类使用RNGCryptoServiceProvider,它是灵活的。例子:

var generator = new PasswordGenerator(minimumLengthPassword: 8,
                                      maximumLengthPassword: 15,
                                      minimumUpperCaseChars: 2,
                                      minimumNumericChars: 3,
                                      minimumSpecialChars: 2);
string password = generator.Generate();

由于Random是不安全的,RNGCryptoServiceProvider是过时的,我最终这样做:

  // possible characters that password can have
  private const string passChars =
       "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
       "abcdefghijklmnopqrstuvwxyz" +
       "0123456789" +
       "!@#$%.-_"
       ;

    public static string GetRandomPassword(int length)
    {
        char[] p = new char[length];
        for (int i = 0; i < length; i++)
            p[i] = passChars[RandomNumberGenerator.GetInt32(0, passChars.Length)];
        return new string(p);
    }

我再加上一个不明智的答案。

我有一个用例,我需要机器-机器通信的随机密码,所以我对人类的可读性没有任何要求。我也没有会员资格。GeneratePassword在我的项目,并不想添加依赖。

我相当肯定会员资格。GeneratePassword做的事情与此类似,但是在这里您可以调整要从中绘制的字符池。

public static class PasswordGenerator
{
    private readonly static Random _rand = new Random();

    public static string Generate(int length = 24)
    {
        const string lower = "abcdefghijklmnopqrstuvwxyz";
        const string upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        const string number = "1234567890";
        const string special = "!@#$%^&*_-=+";

        // Get cryptographically random sequence of bytes
        var bytes = new byte[length];
        new RNGCryptoServiceProvider().GetBytes(bytes);

        // Build up a string using random bytes and character classes
        var res = new StringBuilder();
        foreach(byte b in bytes)
        {
            // Randomly select a character class for each byte
            switch (_rand.Next(4))
            {
                // In each case use mod to project byte b to the correct range
                case 0:
                    res.Append(lower[b % lower.Count()]);
                    break;
                case 1:
                    res.Append(upper[b % upper.Count()]);
                    break;
                case 2:
                    res.Append(number[b % number.Count()]);
                    break;
                case 3:
                    res.Append(special[b % special.Count()]);
                    break;
            }
        }
        return res.ToString();
    }
}

以及一些示例输出:

PasswordGenerator.Generate(12)
"pzY=64@-ChS$"
"BG0OsyLbYnI_"
"l9#5^2&adj_i"
"#++Ws9d$%O%X"
"IWhdIN-#&O^s"

为了消除对使用Random的抱怨:随机性的主要来源仍然是加密RNG。即使你可以确定地预先确定随机产生的序列(假设它只产生1),你仍然不知道下一个被选中的字符(尽管这会限制可能性的范围)。

一个简单的扩展是为不同的字符集添加权重,这就像提高最大值和添加下降情况来增加权重一样简单。

switch (_rand.Next(6))
{
    // Prefer letters 2:1
    case 0:
    case 1:
        res.Append(lower[b % lower.Count()]);
        break;
    case 2:
    case 3:
        res.Append(upper[b % upper.Count()]);
        break;
    case 4:
        res.Append(number[b % number.Count()]);
        break;
    case 5:
        res.Append(special[b % special.Count()]);
        break;
}

对于一个更人性化的随机密码生成器,我曾经使用EFF骰子字列表实现了一个提示系统。