当我们网站上的用户丢失密码并前往"忘记密码"页面时,我们需要给他一个新的临时密码.我真的不介意这是多么随机,或者如果它匹配所有"需要的"强密码规则,我想要做的就是给他们一个密码,以便以后更改.
该应用程序是一个用C#编写的Web应用程序.所以我一直在考虑使用Guid的简单方法.即
Guid.NewGuid().ToString("d").Substring(1,8)
Suggesstions?想法?
总有System.Web.Security.Membership.GeneratePassword(int length, int numberOfNonAlphanumericCharacters
).
public string CreatePassword(int length) { const string valid = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"; StringBuilder res = new StringBuilder(); Random rnd = new Random(); while (0 < length--) { res.Append(valid[rnd.Next(valid.Length)]); } return res.ToString(); }
这样做的好处是能够从生成的密码的可用字符列表中进行选择(例如,仅数字,仅大写或仅小写等).
我的代码的主要目标是:
字符串的分布几乎是一致的(只要它们很小,就不关心微小的偏差)
它为每个参数集输出超过几十亿个字符串.如果您的PRNG仅生成20亿(31位熵)不同的值,则生成8个字符的字符串(~47位熵)是没有意义的.
这是安全的,因为我希望人们将其用于密码或其他安全令牌.
第一个属性是通过将64位值模数为字母大小来实现的.对于小字母(例如问题中的62个字符),这会导致可忽略不计的偏差.第二个和第三个属性是通过使用RNGCryptoServiceProvider
而不是System.Random
.
using System; using System.Security.Cryptography; public static string GetRandomAlphanumericString(int length) { const string alphanumericCharacters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789"; return GetRandomString(length, alphanumericCharacters); } public static string GetRandomString(int length, IEnumerablecharacterSet) { if (length < 0) throw new ArgumentException("length must not be negative", "length"); if (length > int.MaxValue / 8) // 250 million chars ought to be enough for anybody throw new ArgumentException("length is too big", "length"); if (characterSet == null) throw new ArgumentNullException("characterSet"); var characterArray = characterSet.Distinct().ToArray(); if (characterArray.Length == 0) throw new ArgumentException("characterSet must not be empty", "characterSet"); var bytes = new byte[length * 8]; new RNGCryptoServiceProvider().GetBytes(bytes); var result = new char[length]; for (int i = 0; i < length; i++) { ulong value = BitConverter.ToUInt64(bytes, i * 8); result[i] = characterArray[value % (uint)characterArray.Length]; } return new string(result); }
(这是我对如何在C#中生成随机8个字符,字母数字字符串的答案的副本?)
以下是我生成随机令牌的方法:
public string GenerateToken(int length) { RNGCryptoServiceProvider cryptRNG = new RNGCryptoServiceProvider(); byte[] tokenBuffer = new byte[length]; cryptRNG.GetBytes(tokenBuffer); return Convert.ToBase64String(tokenBuffer); }
已经注意到,当它返回base-64字符串时,输出长度始终是4的倍数,额外的空间=
用作填充字符.该length
参数指定字节缓冲区的长度,而不是输出字符串(因此可能不是该参数的最佳名称,现在我考虑一下).这可以控制密码将拥有多少字节的熵.但是,因为base-64使用4个字符的块来编码每个3个字节的输入,如果你要求的长度不是3的倍数,那么会有一些额外的"空间",它将=
用于填充额外.
如果您不喜欢因任何原因使用base-64字符串,则Convert.ToBase64String()
可以使用转换为常规字符串或使用任何Encoding
方法替换调用; 例如.Encoding.UTF8.GetString(tokenBuffer)
- 只需确保选择一个字符集,该字符集可以表示RNG中出现的所有值,并且可以生成与您发送或存储的任何位置兼容的字符.例如,使用Unicode往往会产生大量的中文字符.使用base-64可以保证广泛兼容的字符集,只要你使用一个像样的散列算法,这种字符串的特性就不会使它变得不那么安全.
这是一个更大的,但我认为它看起来更全面:http: //www.obviex.com/Samples/Password.aspx
/////////////////////////////////////////////////////////////////////////////// // SAMPLE: Generates random password, which complies with the strong password // rules and does not contain ambiguous characters. // // To run this sample, create a new Visual C# project using the Console // Application template and replace the contents of the Class1.cs file with // the code below. // // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, // EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED // WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. // // Copyright (C) 2004 Obviex(TM). All rights reserved. // using System; using System.Security.Cryptography; ////// This class can generate random passwords, which do not include ambiguous /// characters, such as I, l, and 1. The generated password will be made of /// 7-bit ASCII symbols. Every four characters will include one lower case /// character, one upper case character, one number, and one special symbol /// (such as '%') in a random order. The password will always start with an /// alpha-numeric character; it will not start with a special symbol (we do /// this because some back-end systems do not like certain special /// characters in the first position). /// public class RandomPassword { // Define default min and max password lengths. private static int DEFAULT_MIN_PASSWORD_LENGTH = 8; private static int DEFAULT_MAX_PASSWORD_LENGTH = 10; // Define supported password characters divided into groups. // You can add (or remove) characters to (from) these groups. private static string PASSWORD_CHARS_LCASE = "abcdefgijkmnopqrstwxyz"; private static string PASSWORD_CHARS_UCASE = "ABCDEFGHJKLMNPQRSTWXYZ"; private static string PASSWORD_CHARS_NUMERIC= "23456789"; private static string PASSWORD_CHARS_SPECIAL= "*$-+?_&=!%{}/"; ////// Generates a random password. /// ////// Randomly generated password. /// ////// The length of the generated password will be determined at /// random. It will be no shorter than the minimum default and /// no longer than maximum default. /// public static string Generate() { return Generate(DEFAULT_MIN_PASSWORD_LENGTH, DEFAULT_MAX_PASSWORD_LENGTH); } ////// Generates a random password of the exact length. /// /// /// Exact password length. /// ////// Randomly generated password. /// public static string Generate(int length) { return Generate(length, length); } ////// Generates a random password. /// /// /// Minimum password length. /// /// /// Maximum password length. /// ////// Randomly generated password. /// ////// The length of the generated password will be determined at /// random and it will fall with the range determined by the /// function parameters. /// public static string Generate(int minLength, int maxLength) { // Make sure that input parameters are valid. if (minLength <= 0 || maxLength <= 0 || minLength > maxLength) return null; // Create a local array containing supported password characters // grouped by types. You can remove character groups from this // array, but doing so will weaken the password strength. char[][] charGroups = new char[][] { PASSWORD_CHARS_LCASE.ToCharArray(), PASSWORD_CHARS_UCASE.ToCharArray(), PASSWORD_CHARS_NUMERIC.ToCharArray(), PASSWORD_CHARS_SPECIAL.ToCharArray() }; // Use this array to track the number of unused characters in each // character group. int[] charsLeftInGroup = new int[charGroups.Length]; // Initially, all characters in each group are not used. for (int i=0; i/// Illustrates the use of the RandomPassword class. /// public class RandomPasswordTest { /// /// The main entry point for the application. /// [STAThread] static void Main(string[] args) { // Print 100 randomly generated passwords (8-to-10 char long). for (int i=0; i<100; i++) Console.WriteLine(RandomPassword.Generate(8, 10)); } } // // END OF FILE ///////////////////////////////////////////////////////////////////////////////
我知道这是一个旧线程,但我有一个相当简单的解决方案供某人使用.易于实施,易于理解且易于验证.
考虑以下要求:
我需要生成一个随机密码,其中包含至少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循环到所需的小写字符数,并在每次迭代时,从小写列表中抓取一个随机项,并将其注入字符串中的随机位置.
然后它重复循环以获得大写字母和数字.
这将返回长度为=的字符串,lowercase + uppercase + numerics
其中所需计数的小写,大写和数字字符以随机顺序放置.
我创建了这个使用RNGCryptoServiceProvider的类,它很灵活.例:
var generator = new PasswordGenerator(minimumLengthPassword: 8, maximumLengthPassword: 15, minimumUpperCaseChars: 2, minimumNumericChars: 3, minimumSpecialChars: 2); string password = generator.Generate();
对于这种密码,我倾向于使用一个可能生成更容易"使用"密码的系统.简短,通常由可发音的片段和一些数字组成,没有字符间歧义(是0还是O?A 1还是I?).就像是
string[] words = { 'bur', 'ler', 'meh', 'ree' }; string word = ""; Random rnd = new Random(); for (i = 0; i < 3; i++) word += words[rnd.Next(words.length)] int numbCount = rnd.Next(4); for (i = 0; i < numbCount; i++) word += (2 + rnd.Next(7)).ToString(); return word;
(直接键入浏览器,因此仅用作指南.另外,添加更多单词).
我不喜欢Membership.GeneratePassword()创建的密码,因为它们太难看并且有太多特殊字符.
此代码生成一个10位数的不太丑的密码.
string password = Guid.NewGuid().ToString("N").ToLower() .Replace("1", "").Replace("o", "").Replace("0","") .Substring(0,10);
当然,我可以使用正则表达式来完成所有替换,但这是更易读和可维护的IMO.