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

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

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

Suggesstions吗?想法吗?


当前回答

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

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

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

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

其他回答

在接受的答案中添加了一些补充代码。它改进了仅使用随机的答案,并允许一些密码选项。我也喜欢KeePass回答中的一些选项,但不想在我的解决方案中包含可执行文件。

private string RandomPassword(int length, bool includeCharacters, bool includeNumbers, bool includeUppercase, bool includeNonAlphaNumericCharacters, bool includeLookAlikes)
{
    if (length < 8 || length > 128) throw new ArgumentOutOfRangeException("length");
    if (!includeCharacters && !includeNumbers && !includeNonAlphaNumericCharacters) throw new ArgumentException("RandomPassword-Key arguments all false, no values would be returned");

    string pw = "";
    do
    {
        pw += System.Web.Security.Membership.GeneratePassword(128, 25);
        pw = RemoveCharacters(pw, includeCharacters, includeNumbers, includeUppercase, includeNonAlphaNumericCharacters, includeLookAlikes);
    } while (pw.Length < length);

    return pw.Substring(0, length);
}

private string RemoveCharacters(string passwordString, bool includeCharacters, bool includeNumbers, bool includeUppercase, bool includeNonAlphaNumericCharacters, bool includeLookAlikes)
{
    if (!includeCharacters)
    {
        var remove = new string[] { "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z" };
        foreach (string r in remove)
        {
            passwordString = passwordString.Replace(r, string.Empty);
            passwordString = passwordString.Replace(r.ToUpper(), string.Empty);
        }
    }

    if (!includeNumbers)
    {
        var remove = new string[] { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" };
        foreach (string r in remove)
            passwordString = passwordString.Replace(r, string.Empty);
    }

    if (!includeUppercase)
        passwordString = passwordString.ToLower();

    if (!includeNonAlphaNumericCharacters)
    {
        var remove = new string[] { "!", "@", "#", "$", "%", "^", "&", "*", "(", ")", "-", "_", "+", "=", "{", "}", "[", "]", "|", "\\", ":", ";", "<", ">", "/", "?", "." };
        foreach (string r in remove)
            passwordString = passwordString.Replace(r, string.Empty);
    }

    if (!includeLookAlikes)
    {
        var remove = new string[] { "(", ")", "0", "O", "o", "1", "i", "I", "l", "|", "!", ":", ";" };
        foreach (string r in remove)
            passwordString = passwordString.Replace(r, string.Empty);
    }

    return passwordString;
}

这是我搜索生成随机密码时的第一个链接,以下内容超出了当前问题的范围,但可能很重要,需要考虑。

假设System.Web.Security.Membership.GeneratePassword是加密安全的,至少有20%的字符是非字母数字。 不确定在这种情况下删除字符和追加字符串是否被认为是良好的实践,并提供足够的熵。 可能需要考虑以某种方式使用SecureString实现内存中的安全密码存储。

我一直对KeePass内置的密码生成器非常满意。因为KeePass是一个。net程序,而且是开源的,所以我决定深入研究一下它的代码。最后,我只是在我的项目中引用了标准应用程序安装中提供的KeePass.exe副本,并编写了下面的代码。多亏了KeePass,你可以看到它是多么灵活。你可以指定长度,包含/不包含哪些字符,等等。

using KeePassLib.Cryptography.PasswordGenerator;
using KeePassLib.Security;


public static string GeneratePassword(int passwordLength, bool lowerCase, bool upperCase, bool digits,
        bool punctuation, bool brackets, bool specialAscii, bool excludeLookAlike)
    {
        var ps = new ProtectedString();
        var profile = new PwProfile();
        profile.CharSet = new PwCharSet();
        profile.CharSet.Clear();

        if (lowerCase)
            profile.CharSet.AddCharSet('l');
        if(upperCase)
            profile.CharSet.AddCharSet('u');
        if(digits)
            profile.CharSet.AddCharSet('d');
        if (punctuation)
            profile.CharSet.AddCharSet('p');
        if (brackets)
            profile.CharSet.AddCharSet('b');
        if (specialAscii)
            profile.CharSet.AddCharSet('s');

        profile.ExcludeLookAlike = excludeLookAlike;
        profile.Length = (uint)passwordLength;
        profile.NoRepeatingCharacters = true;

        KeePassLib.Cryptography.PasswordGenerator.PwGenerator.Generate(out ps, profile, null, _pool);

        return ps.ReadString();
    }

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

我有一个用例,我需要机器-机器通信的随机密码,所以我对人类的可读性没有任何要求。我也没有会员资格。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骰子字列表实现了一个提示系统。

这个包允许你生成一个随机密码,同时流利地指出它应该包含哪些字符(如果需要):

https://github.com/prjseal/PasswordGenerator/

例子:

var pwd = new Password().IncludeLowercase().IncludeUppercase().IncludeSpecial();
var password = pwd.Next();

我创建的这个方法类似于会员资格提供程序中可用的方法。如果你不想在某些应用程序中添加web引用,这是很有用的。

效果很好。

public static string GeneratePassword(int Length, int NonAlphaNumericChars)
    {
        string allowedChars = "abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ0123456789";
        string allowedNonAlphaNum = "!@#$%^&*()_-+=[{]};:<>|./?";
        Random rd = new Random();

        if (NonAlphaNumericChars > Length || Length <= 0 || NonAlphaNumericChars < 0)
            throw new ArgumentOutOfRangeException();

            char[] pass = new char[Length];
            int[] pos = new int[Length];
            int i = 0, j = 0, temp = 0;
            bool flag = false;

            //Random the position values of the pos array for the string Pass
            while (i < Length - 1)
            {
                j = 0;
                flag = false;
                temp = rd.Next(0, Length);
                for (j = 0; j < Length; j++)
                    if (temp == pos[j])
                    {
                        flag = true;
                        j = Length;
                    }

                if (!flag)
                {
                    pos[i] = temp;
                    i++;
                }
            }

            //Random the AlphaNumericChars
            for (i = 0; i < Length - NonAlphaNumericChars; i++)
                pass[i] = allowedChars[rd.Next(0, allowedChars.Length)];

            //Random the NonAlphaNumericChars
            for (i = Length - NonAlphaNumericChars; i < Length; i++)
                pass[i] = allowedNonAlphaNum[rd.Next(0, allowedNonAlphaNum.Length)];

            //Set the sorted array values by the pos array for the rigth posistion
            char[] sorted = new char[Length];
            for (i = 0; i < Length; i++)
                sorted[i] = pass[pos[i]];

            string Pass = new String(sorted);

            return Pass;
    }