我的最终目标是创建一个唯一且无法猜测/预测的网址。此URL的目的是允许用户执行验证其电子邮件地址和重置密码等操作。这些URL将在设定的时间内过期(目前设置为24小时)。
我最初使用Guid
用于此目的,但我现在明白这是介于“正常”和“非常不安全”之间,取决于您倾听的专家。所以,我想我会加强我的代码,为了以防万一。起初我以为我只是坚持使用Guid
,但是从随机字节而不是Guid.NewGuid()
工厂方法生成它。这是我提出的方法:
public static Guid GetRandomGuid()
{
var bytes = new byte[16];
var generator = new RNGCryptoServiceProvider();
generator.GetBytes(bytes);
return new Guid(bytes);
}
我不太清楚使用new Guid(bytes)
而不是Guid.NewGuid()
时究竟发生了什么,但我认为所有这些方法都会产生随机字节数组和存储它在Guid
数据结构中。换句话说,它不再保证是唯一的,它只能保证是随机的。
由于我的网址必须是唯一的和随机,因此这似乎不是一个可靠的解决方案。我现在想,我应该将我的URL基于一个唯一ID(可以是Guid
或者,如果可用的话,数据库自动增加的id)和从{{1生成的随机序列}}
问题
生成验证/密码重置网址的最佳方法是什么,该网址既保证唯一又极难/无法预测/猜测?
我应该通过将唯一字符串与随机字符串连接来构建我的URL吗?
.NET Framework是否有内置方法可以轻松生成可用于URL的唯一和随机(不可预测)序列?
如果没有,是否有可用的开源解决方案?
更新
如果有人有类似要求,我目前正在使用以下方法:
RNGCryptoServiceProvider
如果您发现此问题,请发表评论。
答案 0 :(得分:5)
Guid并不是一种安全功能。创建Guid make no claims about how secure it is的标准,或猜测它是多么容易/多难。 它只是声称它的独特性。
如果您尝试使用Guid来保护您的系统,那么您将没有安全的系统。
答案 1 :(得分:0)
[编辑:我错过了上面对RNGCryptoServiceProvider的调用。对此抱歉。]
RNG生成器(例如RNGCryptoServiceProvider)的问题在于它们不能保证唯一性。如你所知,Guids statistically unlikely是唯一的,但不保证。保证唯一性和随机性的唯一真正方法是生成GUID,然后将其放在可搜索的存储中,如数据库表。无论何时生成新值,请检查它是否已存在。如果是,则丢弃它并生成新值。
答案 2 :(得分:0)
你可以生成128位,"随机,"通过使用随机密钥键入的AES计数器运行计数器的唯一号码。只要使用相同的密钥,就不会重复任何输出。
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);
}
}
}
答案 3 :(得分:0)
获取所有用户登录凭据的md5并将其与Guid.NewGuid()生成的guid连接.ToString()并在您的URL中使用它,它应该可以正常工作。
答案 4 :(得分:0)
使用linkID和Datesent列在数据库中创建一个表,在生成链接发送insert DateTime.Now
到表中并返回linkId时,将linkID设置为activationLink上的querystring参数。
在加载激活页面时,请检索linkId并使用它来唤起存储过程,该过程将在传递相应的linkId作为参数时返回日期,当您获得日期时,您可以添加您希望链接的时间长度使用.AddDays()
/ .AddMonths
保持活动状态(这是日期时间的C#方法)。然后将您回来的日期与今天的日期进行比较。如果已经过了几天或几个月的长度,则会显示错误消息,或者继续并显示页面内容。
我认为您将页面内容保留在面板中并将其设置为visible = "false"
,然后仅在日期仍在范围内时才设置面板visible="true"
。