如何实现密码重置?

我正在研究ASP.NET中的应用程序,并想知道如何实现Password Resetfunction,如果我想推出自己的。

具体来说,我有以下问题:

  • 生成一个难以破解的唯一ID的好方法是什么?
  • 是否应该附加一个计时器? 如果是这样,应该多久?
  • 我应该loggingIP地址吗? 它甚至重要吗?
  • 在“密码重置”屏幕下,我需要什么信息? 只是电子邮件地址 或者,也许电子邮件地址加上他们“知道”的一些信息? (最喜欢的球队,小狗的名字等)

还有其他的事情需要注意吗?

: 其他问题完全掩盖了技术实现。 事实上接受的答案掩盖了血淋淋的细节。 我希望这个问题和随后的答案能够进入细节,我希望通过狭义的措辞来解释这个问题的答案是“绒毛”和“戈尔”。

编辑 :也进入如何将这样的表build模和处理在SQL Server或任何ASP.NET MVC链接到答案的答案,将不胜感激。

很多好的答案在这里,我不打扰重复这一切…

除了一个问题,几乎每一个答案在这里重复,即使它是错的:

Guid是(现实)独特的,统计上不可能猜测

这是不正确的,GUID是非常弱的标识符, 应该被用来允许访问用户的帐户。
如果你检查一下这个结构,你最多可以得到128位的数据……这个现在已经不是很多了。
其中前半部分是典型的不变的(对于发电系统),剩下的一半是时间依赖的(或者其他类似的)。
总而言之,这是一个非常脆弱和容易被强暴的机制。

所以不要使用!

相反,只需使用密码强的随机数生成器(System.Security.Cryptography.RNGCryptoServiceProvider),并获得至less256位的原始熵。

除此之外,还有许多其他答案。

编辑2012年5月22日:作为这个受欢迎的答案的后续行动,我不再在此过程中使用GUID。 像其他stream行的答案一样,我现在使用自己的散列algorithm来生成在URL中发送的密钥。 这也具有缩短的优点。 看看System.Security.Cryptography来生成它们,我通常也使用一个SALT。

首先,不要立即重置用户的密码。

首先,请求时不要立即重置用户的密码。 这是一个安全漏洞,因为有人可能会猜测电子邮件地址(即公司的电子邮件地址),并重新设置密码。 最佳做法通常包括发送到用户的电子邮件地址的“确认”链接,确认他们要重置它。 此链接是您想要发送唯一密钥链接的位置。 我发送一个像我这样的链接: domain.com/User/PasswordReset/xjdk2ms92

是的,在链接上设置一个超时值,并将密钥和超时值存储在后端(如果使用的话,还要加上salt)。 3天的超时是常态,并且在请求重置时确保在networking级别通知用户3天。

使用一个唯一的散列键

我以前的答案说使用GUID。 我现在编辑这个build议大家使用随机生成的散列,例如使用RNGCryptoServiceProvider 。 而且,确保消除散列中的任何“真实的单词”。 我回想起一个特殊的上午6点的电话,一个女人在她的“假设是随机的”中收到了某个“c”字,这个字是开发者做的。 卫生署!

整个程序

  • 用户点击“重置”密码。
  • 用户需要input电子邮件。
  • 用户input电子邮件并点击发送。 不要确认或拒绝电子邮件,因为这也是不好的做法。 简单地说,“如果电子邮件通过validation,我们已经发送了密码重置请求。” 或者一些神秘的东西。
  • 您可以从RNGCryptoServiceProvider创build一个散列,将其作为单独的实体存储在ut_UserPasswordRequests表中并链接回用户。 因此,您可以跟踪旧的请求,并通知用户旧链接已过期。
  • 发送链接到电子邮件。

用户获得链接,如http://domain.com/User/PasswordReset/xjdk2ms92 ,并点击它。

如果链接被validation,您要求一个新的密码。 简单,用户可以设置自己的密码。 或者,在这里设置你自己的密码,并通知他们新的密码在这里(并通过电子邮件发送给他们)。

首先,我们需要知道你已经知道的用户。 显然,你有一个用户名和一个旧密码。 你还知道什么? 你有电子邮件地址吗? 你有关于用户最喜爱的花的数据?

假设你有一个用户名,密码和工作电子邮件地址,你需要添加两个字段到你的用户表(假设它是一个数据库表):一个名为new_passwd_expire的date和一个stringnew_passwd_id。

假设您有用户的电子邮件地址,当有人请求重置密码时,您将更新用户表,如下所示:

 new_passwd_expire = now() + some number of days new_passwd_id = some random string of characters (see below) 

接下来,您将向该地址的用户发送电子邮件:

亲爱的,如此

有人要求在<您的网站名称>处为用户帐户<用户名>申请新密码。 如果您确实要求重置密码,请点击以下链接:

http://example.com/yourscript.lang?update= < new_password_id >

如果该链接不起作用,您可以访问http://example.com/yourscript.lang并在表单中input以下内容:<new_password_id>;

如果您没有要求重置密码,则可以忽略此电子邮件。

谢谢你,yada yada

现在,编码yourscript.lang:这个脚本需要一个表单。 如果在URL上传递var更新,表单只是要求用户的用户名和电子邮件地址。 如果更新未通过,则会要求input用户名,电子邮件地址以及电子邮件中发送的身份validation码。 你也要求一个新的密码(当然两次)。

要validation用户的新密码,请validation用户名,电子邮件地址和ID代码是否全部匹配,请求是否已过期,以及这两个新密码是否匹配。 如果成功,则将用户密码更改为新密码,并清除用户表中的密码重置字段。 此外,请确保将用户login/清除任何与login相关的cookie,并将用户redirect到login页面。

本质上,new_passwd_id字段是只能在密码重置页面上使用的密码。

一个可能的改进:你可以从电子邮件中删除<username>。 “有人要求在这个电子邮件地址的帐户重置密码….”因此,使用户名只有用户知道,如果电子邮件被截获。 我没有这样开始,因为如果有人攻击这个帐户,他们已经知道了用户名。 这join了默默无闻的行为,以防万一有人恶意拦截电子邮件时发生中间人攻击。

至于你的问题:

生成随机string:它不需要是非常随机的。 任何GUID生成器甚至md5(concat(salt,current_timestamp()))就足够了,salt就是用户logging上的东西,就像创build时间戳记帐户一样。 它必须是用户无法看到的东西。

定时器:是的,你需要这个只是为了保持你的数据库健全。 由于您永远不知道电子邮件延迟可能会持续多久,因此不超过一个星期是非常必要的,但至less需要2天。

IP地址:由于电子邮件可能会延迟几天,因此IP地址仅用于日志logging,而不用于validation。 如果你想logging它,那么这样做,否则你不需要它。

重置屏幕:见上面。

希望覆盖它。 祝你好运。

发送到logging电子邮件地址的GUID对于大多数普通应用程序来说可能是足够的 – 超时甚至更好。

毕竟,如果用户的电子邮箱已经被盗用(即黑客拥有电子邮件地址的login/密码),那么你就不能做这些事情了。

您可以通过链接向用户发送电子邮件。 这个链接将包含一些很难猜测的string(如GUID)。 在服务器端,您还将存储与发送给用户相同的string。 现在,当用户按下链接,你可以在你的数据库条目中find一个相同的秘密string并重置密码。

1)为了生成唯一的ID你可以使用安全哈希algorithm。 2)定时器连接? 你的意思是重置密码链接到期吗? 是的,你可以有一个过期设置3)你可以要求一些更多的信息,除了emailIdvalidation..像出生date或一些安全问题4)你也可以生成随机字符,并要求input,也请求..以确保密码请求不是由一些间谍软件或类似的东西自动化..