2009-12-31 144 views
25

我正在寻求在我的网站上实现“忘记密码”功能。我喜欢将包含一段时间后过期的临时一次性使用URL的电子邮件发送给用户的选项。生成临时URL来重置密码

我已经看过以下页面来获得这些想法,但我不知道如何使用ASP.NET和C#实现这一点。正如用户所指出的那样,如果我可以在不将这些信息存储在数据库中的情况下实现这一点,那将是理想的。请指教。

Password reset by emailing temporary passwords

谢谢。

回答

-2

根据您的需求,您可以加密信息,并以类似于以下格式

(UserId)-(ExpireDate) 

加密数据的格式,使该链接,然后对数据进行解密,并从那里采取行动...

原油,但最有可能使用的,并且不需要使用DB

+29

将任何数据包含到密码重置令牌是一种不好的做法。事件是否加密。知道该算法的黑客即使无法访问用户的邮箱,也可以为任何用户重置密码。 – 2012-10-04 08:43:34

+3

-1。这个想法在某种意义上是好的,但不应该使用它,因为Slava在之前的评论中解释了安全问题。 – Mohayemin 2013-03-07 04:34:08

+5

@SlavaNadvorny黑客也需要知道加密算法的关键。你可以假设,如果黑客有权访问加密密钥,他可能也可以访问存储的哈希值,所以是的,这种技术似乎仍然是一个好主意。 – Guillaume 2013-03-22 12:42:47

1

在这里,你的朋友的System.Guid类,因为它会生成一个唯一的(当然,足够的唯一的)128位号:

  • 生成新的GUID(System.Guid.NewGuid())
  • 商店该GUID某处(Application对象也许?)
  • 发送自定义URL在一封电子邮件,该GUID
  • 当用户点击该网站,让他们进入你的电子邮件
  • 发送的密码,如果密码匹配,继续前进,迫使他们进入一个新的密码
+0

+1:感谢这个话题/边信息:-) – 2012-10-08 14:06:53

+3

GUID应该是独一无二的,但不应该是密码强。可能猜测哪个GUID将被创建,从而为特定帐户创建一个令牌。 – Guillaume 2013-03-22 12:46:00

+0

@Guillaume,感谢您的信息,真的有可能吗?你能解释一下它是如何被猜测的吗?我正在考虑使用GUID。 – Don 2014-10-15 07:32:20

59

也许最简单的方法是将要修改的用户表添加2个额外的c或者如果你不想修改现有的表,你可以添加一个名为“UserPasswordReset”或类似的新的从属表。列是这样的:

PasswordResetToken UNIQUEIDENTIFIER, 
PasswordResetExpiration DATETIME 

如果使用附加表的路线走,你所能做的也增加了用户ID列,使其成为一个主键和一个foriegn重要的参考回到你的用户表。还建议使用UNIQUE约束。然后,您只需在您的asp.net应用程序中使用Guid作为标记。

流动可能是这样的:

  1. 用户请求密码重置为他们的帐户
  2. 您插入表中的一个新的记录(或更新他们的用户记录)由PasswordResetExpiration设定一个日期在未来(DateTime.Now.AddDays(1)),并将令牌设置为Guid.NewGuid()
  3. 用查询字符串中的guid向用户发送链接到您的ResetPassword.aspx页面(http://www.yoursite.com/ResetPassword.aspx?token=Guid-here
  4. 使用ResetPassword.aspx页面进行验证令牌和过期字段。 (I.E.确保DateTime.Now < PasswordResetExpiration)
  5. 提供一个简单的表单,允许用户重置此密码。

我知道你想避免修改数据库,但它确实可能是最简单的方法。

+1

安全说明:UNIQUEIDENTIFIER并不意味着提供随机性,并且在这种情况下不安全。基本上,你想要一个无法猜测的重置链接。为了不可能猜到你的重置链接,你需要包含一个随机数字,这个随机数字由一个GUID不是的密码安全的随机数生成器生成。因此,除了2列以外,还需要第三个存储该随机数字作为密码,最后将重置链接中的GUID和密码作为参数发送出去。 – Gudradain 2015-07-20 19:57:13

2

我用一个散列类来创建由当前的日期/时间独有的自动登录和用户的电子邮件地址:

string strNow = DateTime.Now.ToString(); 
string strHash = strNow + strEmail; 
strHash = Hash.GetHash(strHash, Hash.HashType.SHA1); 

得到哈希类:http://www.developerfusion.com/code/4601/create-hashes-md5-sha1-sha256-sha384-sha512/

然后只是把它从使用的网址:

if (Request.QueryString["hash"] != null) 
{ 
       //extract Hash from the URL 
       string strHash = Request.QueryString["hash"]; 
} 
+0

如何从哈希中重新获取电子邮件地址和日期时间,以便您可以自动登录?因为哈希是单向的吗?请教育。 – 2012-03-30 09:21:25

+0

@goths您可以将Hash值存储在数据库中,也可以发送包含URL的电子邮件,并附加用户标识和散列。然后在URL指向的页面上,将2与数据库进行比较。这将是一个基本的解决方案,你需要一些更强大的东西来提高安全性。 – Alex 2012-04-06 23:36:18

+2

对不起,但我没有看到实用程序发送散列编码密钥中的任何信息,如果要将它存储在数据库中的相同信息旁边。唯一需要考虑的是唯一的密钥,而不是任何“真实”信息的加密版本。 Goyuix提出的randow唯一生成的id(请参阅他的答案)是最好的选择,如果您必须发送并存储在数据库中的某些内容才能够在用户单击发送的电子邮件中的链接时找回它。 – 2012-10-08 14:10:35

2

@Alex

您也可以使用.NET中的System.Security.Cryptography类作为散列算法。例如:

using System.Security.Cryptography; 
... 
var hash = SHA256CryptoServiceProvider.Create().ComputeHash(myTokenToHash); 
... 
0

向用户电子邮件发送一些数据|字符串的目标是验证帐户所有者。请注意以下几点:

  • 避免在重置或激活链接时发送重要信息。
  • 这是存储唯一字符串数据连同用户 帐户并将其作为该链接发送的最佳方式。但请注意,如果您只发送一个 部分作为用户电子邮件链接并在页面中检查它,则您的 应用程序可能会通过蛮力或字典 攻击者处于危险之中。检查一个字符串列表以查找一些链接 并更改密码就足够了。我知道这有一点机会,但不是零。

结果: 我认为这是更好,如果你

  1. 结合用户的电子邮件串链接,然后将它们加密 (不散列因为散列值不能反转),并发送至用户 电子邮件。
  2. 用户单击并且您的页面获得加密值。
  3. 解密值。
  4. 提取用户邮件。
  5. 在数据库中查找电子邮件。
  6. 比较来自接收链接的字符串与附加到数据库中的用户 电子邮件的其他链接。

祝你好运。

1

我肯定会在这个过程中包含数据库。一旦请求重置,最好指出帐户被锁定。

例如,如果您因为认为自己的帐户可能已被泄密而更改了自己的密码,那么当您执行更改过程时,您绝对不希望它保持可访问状态。

另外,如果有人真的需要它并具有马力,那么在重置令牌中包含“真实”信息可以被解码。生成一个随机字符串会比较安全,将其保存在该用户所在行的数据库中,然后在单击该链接时键入它。

这给了你两件事情:

1)没有什么解密,因此价值没有什么可以从中获得。 2)用户记录中存在令牌表示重置正在进行中,并应将帐户视为锁定。

0

我会使用哈希码来验证密码重置网址中的详细信息。这一切都可以在不向DB写入任何内容或向攻击者发送任何特权信息的情况下完成。

简要解释正常的密码salt和散列;说盐是1111,密码是password,你要连接这两个字符串并且对字符串1111password进行散列,比如说这会给你一个散列9999,然后你会在你的用户记录中存储原始盐1111和散列9999

当您使用存储盐验证密码时,连接密码尝试,对其进行散列并与存储的散列进行比较。例如asecret变为1111asecret,但散列为8888。这与原始散列不匹配,所以密码匹配失败。

当然盐和哈希通常会正确地生成和计算与建立的加密库(不要发明自己的!)。

对于密码重置URL,我会为用户设置唯一标识符,例如电子邮件地址,请求的日期以及新的散列。这个哈希将从这些细节连接在一起加上已经为用户存储的盐和散列生成。

例如:

Email: [email protected] 
Request Date: 2014-07-17 
Salt: 1111 
Hash: 9999 

生成这些级联的一个新的哈希值,即'[email protected]',说这给人的7777的哈希值。

的网址,然后我产生那么将有电子邮件,请求日期和新的散列:

https:\\www.example.com\[email protected]&requestdate=2014-07-17&hash=7777 

服务器与它的盐和散列将结合电子邮件和提供的日期,并确认它产生的散列与提供的相同。如果这是正确的,那么它将显示重置表单,隐藏在其后面的相同三个参数,否则会显示错误。当输入新密码以防止该表单被欺骗时,它们会重新提交并重新检查。

需要提供电子邮件地址才能发出请求,并且只能通过电子邮件发送到相同的地址。日期几乎没有特定的信息,哈希是不可逆的,所以什么也不给。没有数据写入数据库,任何篡改参数都会导致哈希失败,并且URL会报告错误。

+1

这种方法存在问题。安全的哈希令令牌真的很长。要么将盐整合到散列本身(使其长约20个字符),要么将此独特盐存储在数据库中。如果将salt存储在数据库中,那么也可以存储任何不存在于任何现有数据中的随机令牌。 – martinstoeckli 2014-07-17 16:04:12

+0

@martinstoeckli因为你已经在连接字符串中哈希了一个盐,所以不需要添加另一个盐。 OP确实要求它没有存储在数据库中。 虽然你是对的,但网址很长,正确的散列会使它更长,但我希望链接被点击或复制和粘贴,所以我不认为这是一个问题太多。 – 2014-07-21 16:18:48

+0

我的意思是,盐必须包含在链接可读的形式,否则它是一个关键而不是盐。盐每个标记都是唯一的,这必须存储在数据库中,或者您可以从url中提取它。 – martinstoeckli 2014-07-21 20:14:22