当我们网站上的用户丢失密码并转到丢失密码页面时,我们需要给他一个新的临时密码。我并不介意这有多随机,或者它是否符合所有“所需的”强密码规则,我想做的只是给他们一个他们以后可以更改的密码。
该应用程序是用c#编写的Web应用程序。所以我想刻薄一点,走一条简单的路线,用Guid的一部分。即。
Guid.NewGuid().ToString("d").Substring(1,8)
Suggesstions吗?想法吗?
当我们网站上的用户丢失密码并转到丢失密码页面时,我们需要给他一个新的临时密码。我并不介意这有多随机,或者它是否符合所有“所需的”强密码规则,我想做的只是给他们一个他们以后可以更改的密码。
该应用程序是用c#编写的Web应用程序。所以我想刻薄一点,走一条简单的路线,用Guid的一部分。即。
Guid.NewGuid().ToString("d").Substring(1,8)
Suggesstions吗?想法吗?
当前回答
public string GenerateToken(int length)
{
using (RNGCryptoServiceProvider cryptRNG = new RNGCryptoServiceProvider())
{
byte[] tokenBuffer = new byte[length];
cryptRNG.GetBytes(tokenBuffer);
return Convert.ToBase64String(tokenBuffer);
}
}
(你也可以让这个方法所在的类实现IDisposable,持有对RNGCryptoServiceProvider的引用,并正确地处理它,以避免重复实例化它。)
It's been noted that as this returns a base-64 string, the output length is always a multiple of 4, with the extra space using = as a padding character. The length parameter specifies the length of the byte buffer, not the output string (and is therefore perhaps not the best name for that parameter, now I think about it). This controls how many bytes of entropy the password will have. However, because base-64 uses a 4-character block to encode each 3 bytes of input, if you ask for a length that's not a multiple of 3, there will be some extra "space", and it'll use = to fill the extra.
If you don't like using base-64 strings for any reason, you can replace the Convert.ToBase64String() call with either a conversion to regular string, or with any of the Encoding methods; eg. Encoding.UTF8.GetString(tokenBuffer) - just make sure you pick a character set that can represent the full range of values coming out of the RNG, and that produces characters that are compatible with wherever you're sending or storing this. Using Unicode, for example, tends to give a lot of Chinese characters. Using base-64 guarantees a widely-compatible set of characters, and the characteristics of such a string shouldn't make it any less secure as long as you use a decent hashing algorithm.
其他回答
灵感来自@kitsu的回答。但使用RandomNumberGenerator而不是Random或RNGCryptoServiceProvider(在。net 6中已弃用),并添加了一些特殊字符。
可选参数,用于排除在使用System.Text.Json.JsonSerializer.Serialize时将转义的字符—例如&,它转义为\u0026—以便您可以保证序列化字符串的长度与密码的长度匹配。
适用于。net Core 3.0及以上版本。
public static class PasswordGenerator
{
const string lower = "abcdefghijklmnopqrstuvwxyz";
const string upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const string number = "1234567890";
const string special = "!@#$%^&*()[]{},.:`~_-=+"; // excludes problematic characters like ;'"/\
const string specialJsonSafe = "!@#$%^*()[]{},.:~_-="; // excludes problematic characters like ;'"/\ and &`+
const int lowerLength = 26; // lower.Length
const int upperLength = 26; // upper.Length;
const int numberLength = 10; // number.Length;
const int specialLength = 23; // special.Length;
const int specialJsonSafeLength = 20; // specialJsonSafe.Length;
public static string Generate(int length = 96, bool jsonSafeSpecialCharactersOnly = false)
{
Span<char> result = length < 1024 ? stackalloc char[length] : new char[length].AsSpan();
for (int i = 0; i < length; ++i)
{
switch (RandomNumberGenerator.GetInt32(4))
{
case 0:
result[i] = lower[RandomNumberGenerator.GetInt32(0, lowerLength)];
break;
case 1:
result[i] = upper[RandomNumberGenerator.GetInt32(0, upperLength)];
break;
case 2:
result[i] = number[RandomNumberGenerator.GetInt32(0, numberLength)];
break;
case 3:
if (jsonSafeSpecialCharactersOnly)
{
result[i] = specialJsonSafe[RandomNumberGenerator.GetInt32(0, specialJsonSafeLength)];
}
else
{
result[i] = special[RandomNumberGenerator.GetInt32(0, specialLength)];
}
break;
}
}
return result.ToString();
}
}
这很短,对我来说很有用。
public static string GenerateRandomCode(int length)
{
Random rdm = new Random();
StringBuilder sb = new StringBuilder();
for(int i = 0; i < length; i++)
sb.Append(Convert.ToChar(rdm.Next(101,132)));
return sb.ToString();
}
这是我快速拼凑的东西。
public string GeneratePassword(int len)
{
string res = "";
Random rnd = new Random();
while (res.Length < len) res += (new Func<Random, string>((r) => {
char c = (char)((r.Next(123) * DateTime.Now.Millisecond % 123));
return (Char.IsLetterOrDigit(c)) ? c.ToString() : "";
}))(rnd);
return res;
}
public static string GeneratePassword(int passLength) {
var chars = "abcdefghijklmnopqrstuvwxyz@#$&ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
var random = new Random();
var result = new string(
Enumerable.Repeat(chars, passLength)
.Select(s => s[random.Next(s.Length)])
.ToArray());
return result;
}
我的代码的主要目标是:
弦的分布几乎是均匀的(不关心微小的偏差,只要它们很小) 它为每个参数集输出超过几十亿个字符串。如果您的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, IEnumerable<char> characterSet)
{
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个字符,字母数字字符串的回答的副本?)