在ASP.NET(C#)中实现安全,独特的“一次性”激活URL

我有一个场景,我正在构建的网站的用户需要能够在不必登录的情况下将一些基本信息输入到webform中。 该站点正在使用ASP.NET / C#开发,并使用MSSQL 2005作为其关系数据。

将向用户发送来自站点的电子邮件,为他们提供唯一链接以输入他们所需的特定信息。 该电子邮件与我们在注册论坛等网站时所获得的电子邮件风格非常相似,其中包含一个随机生成的唯一URL参数,专门用于单一目的(例如validation论坛的电子邮件地址)。

我的问题是关于这个问题的安全实现。 我正在考虑使用GUID作为唯一标识符,但我不确定它在安全领域的影响。

  1. GUID是否足够长,以至于不能轻易猜到值(或随着时间的推移强迫)?
  2. .NET的GUID实现是否足够随意,因为在“密钥空间”中生成所有可能值的机会相等?

  3. 如果使用GUID是一种可接受的方法,那么网站是否应该通过URL重写或通过将数据表中的信息与GUID相关联来重定向到信息?

  4. 使用URL重写会隐藏数据的真正来源吗?

  5. 我应该考虑使用TSQL的SELECT NEWID()作为.NET实现的GUID生成器吗?

  6. 我对这个问题的处理方法完全错了吗?

非常感谢,

卡尔

  1. 是的,2 128足够长。
  2. 不,GUID实现旨在生成唯一的 GUID而不是随机的GUID。 您应该使用加密安全随机数生成器(例如RNGCryptoServiceProvider )生成16个随机字节并使用它初始化Guid结构。
  3. 是的,这是一种可接受的方法。 两者都有效。
  4. 是的,如果你没有透露任何其他线索
  5. 不, goto 2
  6. 不,这很好。 您只需使用加密安全随机数生成器来生成GUID。
  1. 不,GUID不是完全随机的,并且大多数位是静态的或容易猜测的。
  2. 不,它们不是随机的,请参阅1.实际上,实际上有非常少量的位实际上是随机的,并且在那时并非加密强随机。
  3. 不是,见1和2。
  4. 你可以,但不需要…最后看到我的解决方案。
  5. 不,见1和2
  6. 是。

你应该使用什么而不是GUID,是一个加密强大的随机数生成器 – 使用System.Security.Cryptography.RNGCryptoServiceProvider ,生成长(比方说,32字节)数据串,然后base64编码 。
此外,假设这是某种敏感数据注册,您需要限制链接的有效性,比如60分钟或24小时 – 取决于您的网站。
您需要将这些值的映射保留给特定用户。 然后,您可以根据需要自动向他提供正确的表格。 不需要进行url重写,只需将其用作用户的标识符(在此页面上)。
当然,不要忘记这个URL应该是HTTPS …

顺便说一句,只是一个注释 – 在电子邮件中放置某种forms的文本的好习惯,解释用户不应该点击匿名电子邮件中的链接,通常你的网站不会发送,他们不应该在点击blablabla后输入密码… 。

哦,差点忘了 – 你应该考虑的另一个问题是如果用户想要发送几封电子邮件会发生什么,例如点击几次注册。 他能一遍又一遍地做到这一点,并获得许多有效的URL吗? 只有最后一个有效吗? 或者也许一遍又一遍地重新发送相同的值? 当然,如果一个匿名用户可以提出这个电子邮件的请求,那么DoS可能会成为一个问题…更不用说如果他输入他自己的电子邮件,他也可以输入任何随机地址,充斥着一些可怜的笨蛋收件箱并可能导致您的邮件服务器被列入黑名单……
没有人正确的答案,但需要在您的申请背景下加以考虑。

它可能有点矫枉过正,但您可以使用您的guid(NewGuid很好)将其电子邮件地址用SHA1 哈希作为哈希盐并将其放在URL中。 然后,当他们到达您的页面时,您可以询问他们的电子邮件地址,检索guid并重新计算哈希以进行validation。 即使有人知道要尝试哪些电子邮件地址,他们也永远无法在不了解您所使用的guid的情况下生成哈希冲突(或者它会让他们花费很长时间:)。 当然,您必须将他们的电子邮件和哈希盐guid保存在数据库中。

我建议只使用一个普通的随机数,例如来自RNGCryptoServiceProvider.GetBytes的字节。 GUID并不意味着完全随机。 它们有固定位,有些版本使用你的MAC地址。 GetBytes还为您提供了使用超过128位的选项(尽管这应该是充足的)。

我认为最好不要将用户的数据放在url中。 虽然HTTPS可以在传输过程中保护它,但它可能仍然在用户的浏览器历史记录中。 最好使用POST并将随机数与数据库的一行相关联。

首先,如果可能,您应该通过限制查询的吞吐量来限制暴力(例如,每秒每秒IP的有限尝试次数,以及每秒有限的总尝试次数)。

根据GUID生成算法,这可能不是一个好主意。 虽然最近的实现应该“通常足够好”,但值可以有很多可预测性。 最近的实现作为.NET中使用的实现应用哈希,否则您有明确可识别的MAC地址字段和自引导以来的时间。 但是,可能的值是有限的,因此您没有真正的128个随机位。

如果安全是首要任务,我会选择一个加密强大的随机数生成器 ,并构建一串随机字符。 这也使oyu独立于一个易于猜测的算法(因为guid.ToString()很容易被识别出来),在不久的将来可能会发现攻击。

如果满足这些条件,我认为在查询字符串中使用密钥没有问题。

使用linkID和Datesent列在数据库中创建一个表,在生成链接时将插入DateTime.Now发送到表中并返回linkId,在activationLink上将linkID设置为querystring参数。 在激活页面的加载时,检索linkId并使用它来唤起存储过程,该过程将在传递对应的linkId作为参数时返回日期,当您获得日期时,您可以添加您希望链接保持活动的时间长度使用.AddDays()/。AddMonths这是datetime的C#方法。 然后比较你回来的日期和今天的日期。 如果已经过了几天或几个月的长度会给出错误消息,否则继续并显示页面内容。 我觉得你将页面的内容保存在一个面板中,然后将其设置为vissible =“false”,如果日期仍在范围内,则只使面板可见=“true”。