C# 在C中生成唯一的*和*随机URL#
我的最终目标是创建一个唯一且无法猜测/预测的URL。此URL的目的是允许用户执行验证其电子邮件地址和重置密码等操作。这些URL将在设定的时间内过期(当前设置为24小时) 我最初使用的是C# 在C中生成唯一的*和*随机URL#,c#,security,authentication,cryptography,guid,C#,Security,Authentication,Cryptography,Guid,我的最终目标是创建一个唯一且无法猜测/预测的URL。此URL的目的是允许用户执行验证其电子邮件地址和重置密码等操作。这些URL将在设定的时间内过期(当前设置为24小时) 我最初使用的是Guid,但现在我知道这介于“很好”和“非常不安全”之间,这取决于你听的是哪位专家。所以,我想我应该加强我的代码,以防万一。起初我认为我应该坚持使用Guid,但它是从随机字节生成的,而不是Guid.NewGuid()工厂方法。以下是我提出的方法: public static Guid GetRandomGuid()
Guid
,但现在我知道这介于“很好”和“非常不安全”之间,这取决于你听的是哪位专家。所以,我想我应该加强我的代码,以防万一。起初我认为我应该坚持使用Guid
,但它是从随机字节生成的,而不是Guid.NewGuid()
工厂方法。以下是我提出的方法:
public static Guid GetRandomGuid()
{
var bytes = new byte[16];
var generator = new RNGCryptoServiceProvider();
generator.GetBytes(bytes);
return new Guid(bytes);
}
我不太清楚使用NewGuid(bytes)
而不是Guid.NewGuid()
时会发生什么,但我认为这种方法所做的只是生成一个随机字节数组并将其存储在Guid
数据结构中。换句话说,它不再保证是唯一的,它只保证是随机的
由于我的URL需要是唯一的和随机的,这似乎不是一个可靠的解决方案。我现在在想,我的URL应该基于一个唯一ID(可以是Guid
,或者,如果可用,数据库自动递增ID)和从RNGCryptoServiceProvider
生成的随机序列的组合
问题
生成保证唯一且极难/不可能预测/猜测的验证/密码重置URL的最佳方法是什么
- 我是否应该简单地通过将唯一字符串与随机字符串连接来构造URL
- NET Framework是否有一种内置方式可以轻松生成可用于URL的唯一且随机(不可预测)的序列
- 如果没有,是否有一个好的开源解决方案
public static string GenerateUniqueRandomToken(int uniqueId)
// generates a unique, random, and alphanumeric token
{
const string availableChars =
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
using (var generator = new RNGCryptoServiceProvider())
{
var bytes = new byte[16];
generator.GetBytes(bytes);
var chars = bytes
.Select(b => availableChars[b % availableChars.Length]);
var token = new string(chars.ToArray());
return uniqueId + token;
}
}
如果您发现这方面有任何问题,请发表意见。Guid并不意味着是一种安全功能。创建Guid的标准,或者猜测它有多容易/难它只是宣称它的独特性。
如果您试图使用Guid保护您的系统,则您将无法获得安全的系统。[编辑:我错过了与上述RNGCryptoServiceProvider的通话。对此深表歉意。] 对于您的案例,RNG生成器(如RNGCryptoServiceProvider)的问题在于它们不能保证唯一性。正如您所知,guid是唯一的,但不能保证它是唯一的。保证唯一性和随机性的唯一真正方法是生成GUID,就像您将其放入可搜索存储区(如数据库表)中一样。每当生成新值时,请检查该值是否尚未存在。如果是,则丢弃它并生成一个新值。您可以通过使用随机密钥键入的AES计数器运行计数器来生成128位“随机”唯一数字。只要使用相同的键,就不会重复任何输出
static byte[] AESCounter(byte[] key, ulong counter) {
byte[] InputBlock = new byte[16];
InputBlock[0] = (byte)(counter & 0xffL);
InputBlock[1] = (byte)((counter & 0xff00L) >> 8);
InputBlock[2] = (byte)((counter & 0xff0000L) >> 16);
InputBlock[3] = (byte)((counter & 0xff000000L) >> 24);
InputBlock[4] = (byte)((counter & 0xff00000000L) >> 32);
InputBlock[5] = (byte)((counter & 0xff0000000000L) >> 40);
InputBlock[6] = (byte)((counter & 0xff000000000000L) >> 48);
InputBlock[7] = (byte)((counter & 0xff00000000000000L) >> 54);
using (AesCryptoServiceProvider AES = new AesCryptoServiceProvider())
{
AES.Key = key;
AES.Mode = CipherMode.ECB;
AES.Padding = PaddingMode.None;
using (ICryptoTransform Encryptor = AES.CreateEncryptor())
{
return Encryptor.TransformFinalBlock(InputBlock, 0, 16);
}
}
}
获取所有用户登录凭据的md5,并将其与guid.NewGuid().ToString()生成的guid连接起来,并在url中使用它,它应该可以正常工作。在数据库中创建一个带有linkID和Datesent列的表,在生成链接send insert
DateTime时。现在将
插入到表中并返回linkID,将linkID设置为activationLink上的querystring参数
加载激活页面时,检索linkId并使用它调用一个存储过程,该存储过程将返回作为参数传递相应linkId时的日期,当您返回日期时,您可以使用.AddDays()
/.AddMonths
(这是datetime的C方法)添加希望链接保持活动的时间。然后比较你回来的日期和今天的日期。如果超过了天数或月份,则给出错误消息,否则继续并显示页面内容
我建议您将页面内容保留在面板中,并将其设置为
visible=“false”
,然后仅在日期仍在范围内时才将面板设置为visible=“true”
。答案对您有帮助吗?我怀疑这将是您的最佳选择。它显然不符合GUID标准。看起来您只是创建了一个16字节的随机数,而不是GUID。@Gabe,是的,请参阅我的编辑。似乎只是生成一个GUID,然后使用该GUID的哈希将为您提供所需的(唯一性和随机性)。我的代码过去只是GUID.NewGuid()
。我编写上述方法是为了提高安全性。我尝试使用此方法所做的是使用加密随机数生成器生成字节,然后简单地将这些字节存储在Guid
数据结构中(用于数据库存储)。这不是我的代码所做的吗?如果不是,你有什么建议?我使用Guid
s为密码重置等生成唯一的URL。所有这些URL在发布后24小时过期。我认为问题在于Guid本质上是可预测的,因为它遵循特定的规则。为什么不根据您自己的一组规则创建一个随机加密散列呢。您可以根据用户名和特定于服务器设置的其他信息进行设置。。。如果不熟悉您的服务器,这基本上是不可能猜测的。GUID是特定的,规则是已知的,因此它在理论上是可以猜测的,尽管在数学上是不可能的。哈希的问题是它不能保证是唯一的。我很确定我在这里所做的也不能保证是独一无二的。但我需要唯一性和随机性。请仔细查看我的代码。我已经在使用RNGCrptoServiceProvider了。@DanM我深表歉意。我重写了我的作品