回顾我的设计:网站密码重置工具

Posted

技术标签:

【中文标题】回顾我的设计:网站密码重置工具【英文标题】:Review my design: Password resetting facility for web site 【发布时间】:2011-03-14 09:38:47 【问题描述】:

当有人丢失密码时,他们会单击丢失或忘记的密码链接。 他们需要输入他们的电子邮件地址,然后回答他们自己的秘密问题 如果秘密问题是正确的,将向他们发送一封电子邮件,其中包含 24 小时后过期的链接。

在发送电子邮件时,会在包含此信息的数据库表中输入一条记录: - 需要重设密码的人的电子邮件 - 重置密码将过期的小时 - 提交重置密码请求的小时数。

发送的链接将引导用户进入一个允许他们输入新密码的表单。 在此表单中,他们需要输入他们的电子邮件地址和密码 X2。

当他们点击提交时,将对 db 进行检查以确保电子邮件有效(密码正在重置)并且尚未过期(通过比较两个日期以查看过期时间是否已过,即 24 小时)

如果电子邮件有效且尚未过期,并且两个密码匹配且满足最低要求,则应用新密码。

成功时会给出确认消息。

第一季度。这是密码恢复的好模型吗? Q2。如何确保发送到用户地址的链接是唯一的?没有人会得到相同的链接?这样就没有人可以只进入密码重置页面并尝试不同的电子邮件,而是让每个需要重置的帐户都有自己的唯一 URL,该 URL 仅适用于该帐户。

关于第二季度:

我在想,当用户请求重置密码时,会生成一个随机唯一 ID,并将其存储在 24 小时后过期的同一记录中。这个随机唯一 id 的列可以称为“摆脱”

将发送给用户的电子邮件中的链接将以 ?rid=xxxxxxxxxxxxx 结尾

当用户在重置密码的页面点击提交时,页面顶部的“rid”用于从db中获取对应的邮箱地址,与表单中的邮箱地址进行对比。这样做可以确保每个密码重置案例都有自己的唯一 URL,其他帐户无法使用该 URL 重置其密码。

这是一个可行的解决方案吗?

任何贡献或建议将不胜感激。

【问题讨论】:

【参考方案1】:

第一季度。恕我直言,有一个缺陷。为什么要求用户输入新密码?我宁愿生成一个新的随机密码并发送给他。收到后,用户可以使用这个随机生成的密码登录,然后在他/她的个人资料中更改。

我建议在大多数网站上使用以下系统:

    用户在“密码重置”表单中输入邮件地址。 邮件已通过验证(即,数据库中是否存在使用此邮件地址的用户?) 新密码随机生成并通过邮件发送,然后进行加盐/哈希处理并保存到数据库中。 用户登录。

简单通用,不会迷路。

现在,您可以通过以下方式提高安全性(减少滥用):

设置密码重置比率。提交表单后,IP 地址和提交的数据就会被记住:现在,在几分钟内,同一个 IP 地址的任何人都无法再重置密码了。 新生成的密码不会替换旧密码:相反,两者都可以使用。想象一下有人重置了另一个用户的密码。如果该用户尚未阅读或收到使用新密码的邮件,他/她必须仍然能够使用旧密码登录。

顺便说一句,这只是我的个人意见,除非需要,否则不要提供秘密问答功能。我很难记住我在哪里回答了什么,所以我可能会比密码更容易忘记答案。

【讨论】:

+1:我讨厌秘密问题...首先,我提供答案,然后在我的信息框等的 Facebook 上发布它。诸如“母亲的娘家姓”或“我长大的城市”太容易研究了。其次,我很少记得我提供的答案......基本上,我觉得它削弱了实际拥有安全密码的安全性。此外,您已经知道电子邮件是合法的(因为它是注册的)所以为什么不发送电子邮件链接进行重置等。 你看到了什么缺陷?发送一个适合一次登录的随机密码或一个适合一次登录的随机链接具有大致相同的安全性。该链接的主要优点是用户可以简单地忽略错误的重置请求。如果您发送随机密码,他们必须对虚假请求采取行动(将密码改回)。我也不认为一次有两个密码是一个好主意。这将减轻蛮力攻击,只是轻微的,但仍然如此。只要用户控制他们的电子邮件,他们就不必担心错误重置。 @Matthew Flaschen:缺陷是要求用户输入密码。作为用户和开发人员,这对我来说都很奇怪。作为用户,我希望收到一个新密码。作为一名开发人员,我不喜欢将同一件事重复两次的想法:您会在三个页面上进行密码安全检查或提交数据控制(注册+配置文件+密码更改)?如果密码足够长,生成随机密码不会增加暴力破解风险。虚假请求的坏处不是安全问题,而是用户会因为收到太多邮件而生气。 发送重置链接是一次性使用密码。这里唯一缺少的细节是,如果之前使用过该链接,您应该在他们点击该链接时提醒他们,并重置密码(因此可能有人已经发送了该链接)。只要密码没有更改,并且链接没有过期,那么这不是问题。但是,如果您点击链接并且密码已重置,则可能存在问题。处理这有点麻烦(因为用户稍后可能只是不小心点击了链接)。 另外,一个人不能完全控制他们的电子邮件,而且大多数电子邮件都是在互联网上以明文形式传输的。电线嗅探器、爱管闲事的管理员、共享计算机的人都是从电子邮件中获取敏感信息的媒介。我建议的另一件事是每次更改密码时通知帐户持有人。因此,正常的重置处理会让用户看到重置电子邮件,然后是密码更改通知电子邮件。如果他们在单击链接之前看到密码更改,则存在问题。并在“所有者”更改之前发送电子邮件。【参考方案2】:

最佳:

    通过 OpenID 登录。更少的编码复杂性、更少的点击、更少的输入、更少的时间浪费。 完成。问题没有实际意义。不用再担心了,这个问题已经有人解决了。

有十亿个网站实施了十亿个身份验证方案,在 99.999% 的情况下这是不必要的。作为用户,为什么我应该相信您作为开发人员不会以纯文本形式存储我的密码或泄露密码或自己被黑客入侵?很少有人为每个网站使用不同的密码...

如果这不可能,那么 make 就尽可能地轻松:

    我点击了“忘记密码?”关联。如果我已经输入了电子邮件(例如在登录尝试失败后),这会自动发送一封邮件。如果我还没有输入,只需隐藏密码字段并告诉我这样做。不要重新加载或将我转发到其他页面。 我得到了一个带有某个键的链接(例如https://site.com/account/reset?key=a890ea8219175f890b7c123ee74a22)。一些与我的帐户相关联的唯一哈希值,并在这么多小时后过期。尽可能使用 SSL。 我点击链接,然后您通过密钥获取我的帐户详细信息,确保它有效且未过期。我输入了两次新密码。我已经知道我的电子邮件地址是什么,你也知道我的电子邮件地址是什么,而且任何潜在的黑客也会知道我的电子邮件地址是什么,所以不要让我输入它。让链接持续一整天是多余的。在一个小时或更短的时间内完成。 我讨厌安全问题。不要这样问我。它基本上只是故意降低安全性的第二个密码,因此您将永远记住它。我没有飞行常客里程,我不知道我母亲的娘家姓等等。别说了。我知道它的作用是阻止可能入侵您电子邮件的陌生人,但除非您是 PayPal,否则我认为这只是过度设计。 当您确认密码匹配并且可以接受时,更新数据库(仅存储我的密码的加盐哈希,而不是密码本身!)并立即让我登录不要将我重定向到登录页面,我必须重新输入我已经多次给你的信息(即使你已经知道是我并且足够信任我来更改我自己的密码)。这太烦人了。 用户不耐烦。

我也不喜欢基于以下情况随机生成的密码:

    通常我只是从邮件中复制粘贴密码。复制粘贴密码是您不希望用户这样做的事情。 我必须手动更改密码,这意味着在用户控制面板或帐户设置中乱搞。我越来越不耐烦了!在我使用一次性密码登录的那一刻,您可能会接受“更改密码”,但这意味着增加了代码复杂性。您现在需要为此添加一个标志、添加另一个重定向、处理用户输入新密码超时等情况。 因为我只是人类,而且人类患有多动症,我通常会忘记执行上述操作,最终得到一个垃圾密码,我必须在下次需要登录时从我的电子邮件中查找并复制.我的错,但我仍然会为此责怪您的网站。 ;-)

随机生成的密码解决方案也暗示了您将始终使用基于密码的解决方案的心态,而基于链接的身份验证似乎是可用性和安全性的未来(OpenID 等)(我不想要一百个小网站知道我的登录详细信息!)。

更新以回应评论:

为什么哈希应该足够:如果黑客可以猜出您生成的哈希的全部 128+ 位(比如说)(并且在一小时内),那么他或她为什么不也能猜出邮箱吗?我知道询问电子邮件和/或安全问题“感觉”更安全,但如果你仔细想想,电子邮件通常是非常可预测和统一的,熵率很低。我怀疑它们是否包含超过 50 位的信息。 (可能要少得多。)我敢打赌,我会比 50 位随机整数更早地猜出你的电子邮件。但如果真的很担心,您需要做的就是在哈希中添加更多位。 256 位左右应该用于过度杀伤模式——SHA256(salt, email, old pw hash, time stamp, maybe some bytes from /dev/urandom) 或类似的......如果黑客可以预测到,那么你真的无能为力。显然他控制了黑客帝国,如果他愿意,他可以将他的思想投射到你硬盘内的磁盘上。

Still Pro-OpenID:我访问的任何需要我创建用户的新站点都应该非常令人信服地说明他们为什么想知道我的(一次性)密码以及他们为我提供的安全性该 OpenID 或 Google/Facebook/等。没有——或者为什么他们不信任谷歌/Facebook/等。没有人(据我所知)到处记住 30 个不同的密码。通常人们会重复使用它们,所以如果这些第三方网站创建者愿意,他们很容易欺骗他们的用户。如果我使用我通常的信息在您的网站上注册,如果您愿意,您可以立即接管我的 Last.FM 和 Reddit 帐户,以及我使用过几次但忘记的十几个网站。事实上,在现代,我有点预计网站如果他们想要他们严格不需要的详细信息,要么是无知的,要么是有恶意的,所以这就是我称之为一次性密码的原因——每个注册感觉就像我在说“在这里,拥有我的 Reddit 帐户,它与我将用于您的网站的 L/P 相同(否则我会忘记)。没关系,我不是特别依恋无论如何。”当然,如果 Google 愿意,他们实际上可以接管我的在线自我的所有,但现在我会比你更信任 Google(无意冒犯!)。

【讨论】:

我不同意 OpenID 解决方案。从用户的角度来看,输入用户名和密码并点击“提交”比重定向到另一个网站要容易得多,搜索 URL(WTF?为什么我不能只使用我的短用户名,必须输入这个长 URL?),输入输入密码,点击“提交”并再次被重定向。 我唯一的分歧在于第 3 步。我必须确认我没有盗用此 URL 或随机找到它(通过输入我的用户名/电子邮件)。这消除了弱或可预测的“密钥”的风险。而且,在 OpenID 上 +1,虽然这也是“已存档的电子邮件”的一种形式 - 它只是通过第 3 方而不是用户进行身份验证。 @MainMa:这只是一个糟糕的实现。尝试从 ***.com 注销并重新登录。对我来说,只需单击一个链接,它就会自动让我登录(因为我已经用 Google 登录了)。应该是这样的! @Yang:是的,但这是一个权衡,在几乎所有情况下,我都会选择不需要我再次输入电子邮件的网站(我觉得我需要每天输入五次,我已经厌倦了)。我已经相信该网站不会泄露您的个人信息/纯文本密码/电子邮件,因此相信他们能够胜任生成密钥是一个较短的信念飞跃(至少对我而言)。 +1:我完全同意这个秘密问题。它IS只是故意降低安全性的第二个密码。 (这很愚蠢)【参考方案3】:

首先,我建议您将密码重置视为安全的商业交易。 SSL 开启,并且单个请求独立于同一帐户的其他请求。生成一个随机的、不可重复使用的事务 ID,并将其与此单一请求相关联,以重置密码。然后,在您发送给他们的电子邮件中,将交易 ID 与 URL 一起嵌入:

http://www.yoursite.com/passwordreset/?id=e3dXY81fr98c6v1

这种所谓的密码重置交易应该与帐户相关联,并具有与密码重置相关联的元数据,例如请求日期和到期日期。帐户本身应该只知道有/正在等待的密码重置与其相关联。

此外,当用户要求重设密码时,请忘记秘密问题 - 向他们发送您应该已经存档的电子邮件会更加安全。 (如果你不这样做,那就开始收集它们!) - 更好的是,使用他们的电子邮件地址作为他们的用户名。

当用户从该交易 ID URL 输入新密码时,您相信它就是您认为的那个人。为确保这一点,您只需要求他们重新输入他们的用户名(您已经确认您正在这样做)。

【讨论】:

秘密问答即将发布。你指的那封电子邮件应该已经存档了,它会拥有唯一的 URL 吗? 是的。文件中的电子邮件地址是接收链接的地址。

以上是关于回顾我的设计:网站密码重置工具的主要内容,如果未能解决你的问题,请参考以下文章

使用设计发送重置密码说明

密码重置阻止访问 phpmyadmin

WEB安全新玩法 [4] 防护邮箱密码重置漏洞

mandrill 破解重置密码指令与设计 2.2.3

密码重置哈希的有效期应该是多久?

Rails 重置密码电子邮件未触发