一次性密码重置链接是否有安全的替代方案?

信息安全 密码
2021-09-04 03:31:40

我们目前有一个我认为是处理密码重置的非常标准的方案。我们的重置链接是一次性链接:它们在被访问后立即失效,即使用户实际上并没有重置他们的密码。

但是,我们的客户主要是 (99%) 具有积极垃圾邮件过滤功能的企业。特别是,我们的一些最大客户(学区)安装了垃圾邮件过滤器来执行链接扫描。作为算法的一部分,他们访问电子邮件中的 [最多 N] 个链接。当用户请求重置密码时,垃圾邮件过滤器的访问会在用户看到链接之前“过期”。

有没有同样安全的一次性链接的替代品?还是足够安全以属于可接受的实践范围?

我们还需要考虑可用性。我们的客户通常与您所能获得的一样非技术。因此,理想情况下,密码重置过程对用户来说不会变得 [多] 复杂。


到目前为止,这是我们的想法:

  • 将重置令牌存储在会话中。当原始浏览器会话打开和/或密码实际上尚未重置时,该链接将保持活动状态。对于使用两种不同设备进行电子邮件和浏览(例如,手机上的电子邮件 + 笔记本电脑进行浏览)的用户来说,这可能会使过程复杂化。
  • N 分钟后使链接失效。我想我已经看到了。但是,我不知道什么时间限制是可用和安全之间可接受的平衡。
  • 仅在提交表单后使链接失效。一些用户可能会访问该链接,将其放入浏览器历史记录中,但从不提交表单。这是可接受的风险水平吗?
4个回答

与往常一样,您必须考虑您试图保护的资产的价值,以便正确评估安全程序是否足够。通常,当您的资产价值较高时,您会愿意接受较低的可用性。

这意味着除了您自己以外的任何人都无法估计给定的解决方案是否足够安全。

话虽如此,解决您的问题的一种简单方法不是让您的链接立即过期,而是让它们在一段时间后或密码被重置后过期(以先到者为准)。

为了确定这对您来说是否足够安全,并假设您对当前设置感到满意,您需要考虑以下更改:

现在可以多次重复使用相同的链接。这可能会削弱系统的安全性。

但是,您目前的假设是不正确的:第一个访问链接的人是合法用户。显然不是这样(正如您所注意到的)。结果是,您并没有通过让链接在首次访问后立即过期来真正提高整体安全性。

因此,在我看来,更改访问令牌的过期方式似乎是一个更好的解决方案:您可以在不影响整体系统安全性的情况下提高可用性。

但是,您可能会考虑在使用重置链接时在您登陆的页面中包含一些二级验证。可以以某种方式提高您对用户身份的信心的东西(通常会使用“安全问题”,尽管该模型不是很好)。

我看不到您描述的一次性密码重置链接的安全性。大多数单次使用的链接只有在更改密码时才无效,而不是在第一次加载页面时无效。意外按下重新加载或 F5 将使请求无效?这是某种非常糟糕的用户体验。

所以让我们考虑一下:用户订购密码链接,可能会发生两件事:

  1. “黑客”首先收到邮件。通过使用您的系统,实际用户甚至没有机会打开此链接,这对用户和您都非常不利。但是在这种情况下,让链接在第一次使用时过期并没有额外的安全性。
  2. 用户根据需要获取邮件。这里一切正常,但如果意外刷新,用户必须从订购新链接开始。

为了使系统更安全,您可以构建一个系统,如果他/她不是更改旧密码的人,则会向用户发送额外的邮件,其中包含“恢复”旧密码的链接。希望您将旧密码以明文形式发送给用户(您甚至不应该这样做)。我的意思是对旧密码哈希和盐进行历史记录,如果用户单击“还原”,您只需再次使用旧哈希和密码。当然,如果邮件帐户遭到入侵,这将无济于事,但对于您的示例,使用存储重置链接的公共计算机,它会有所帮助。

此外,您可以在密码更改后的前 X 天禁止更改帐户邮件。这样一来,黑客就无法完全锁定用户(只要邮件帐户不受影响,但在这种情况下,您无能为力)。

另一种选择是在注册后给用户一个代码(每个老式字母以获得最佳安全性,如果这太贵了,当用户第一次登录并明确要求打印出来时,在页面本身上显示它 -仍然比将其发送到可能受损的邮件帐户更好),这就像给定帐户的紧急恢复一样。例如,当输入此代码时,无论发生什么情况,用户都可以输入新的邮件和密码来访问该帐户。但是这段代码必须非常安全,并且绝对不能保存在任何计算机上。

使用双重身份验证可以增加更多安全性,就像您可以与 Google、GitHub 等一起使用一样。您甚至可以使用Google的系统,因此您不必自己构建所有内容。这样,攻击者必须窃取用户的手机 - 使随机攻击成为不可能。

最后,非常重要的一点:永远不要通过邮件发送密码。我见过很多这样做的大网站,这不可能是一个好主意!

真正的威胁是帐户可能被劫持目前,您的安全性基于保持密码重置链接的机密性,因为任何人都可以随意设置新密码。使用一次性链接无济于事,因为您不知道第一个访问者是实际用户还是冒名顶替者。

为了改善您的情况,有三种选择

  • 使用安全介质而不是未加密的电子邮件,对密码重置链接保密例如 PGP 加密的电子邮件、SMS(未加密但更难拦截)、TextSecure 消息、纸质信件……
  • 不要依赖链接来保密然后你需要一些其他的方式来验证用户。我能想象的所有例子都是昂贵的:邮政服务发送的更复杂的密码(如 PUK),发送带有个人信息的传真(也可以是伪造的,但更困难),只有用户才能回答的其他问题...
  • 保留您当前的解决方案,允许多次访问密码重置页面,在定义的时间段(例如 2 小时)后拒绝尝试,并希望您的网络是安全的。(轶事:直到 2013 年,德国的大多数电子邮件提供商都在交换未加密的电子邮件。)

我正在考虑自己实施的解决此问题的一种方法可以如下工作:

  1. 用户打开密码重置页面,该页面有一个带有电子邮件地址字段的表单。
  2. 用户使用他们的电子邮件地址发布表单
  3. 服务器向用户输入的电子邮件地址发送一次性密码。
  4. 服务器使用包含以下内容的新表单回复 POST 请求:
    • 具有秘密值的隐藏字段
    • 用于输入一次性密码的文本字段
    • 用于输入新密码的两个密码字段
  5. 在提交第二个表单时,服务器验证表单中的秘密值和输入的一次性密码确实相互对应。此外,它会验证这些值不超过 x 小时(对于 1 到 24 之间的某些 x)。
  6. 如果一切输入正确,密码将被重置。

这类似于使用会话 cookie,但表单字段中的秘密值可能不如会话 cookie 持久。可以组合这样,第一个 POST 请求在电子邮件中创建三个值,在 POST 回复中的 cookie 和表单字段中创建两个值,第二个 POST 请求必须包含所有三个值才能重置密码。

这种方法的一种变体,我也在考虑如下:

  1. 用户打开密码重置页面,该页面会通知他们与网页(或子域)位于同一域的一次性电子邮件地址。此外,该页面包含一个带有隐藏字段的表单,该字段带有一个秘密值和一个一次性密码字段。
  2. 用户向他们被告知的地址发送电子邮件。
  3. 结束时DATA,接收邮件服务器立即开始向用户的电子邮件地址发送回复。此回复将包含一次性密码。
  4. 发送给用户的一次性密码现在从电子邮件复制到表单中。
  5. 服务器验证隐藏字段和一次性密码是否相互对应(通过一次性电子邮件地址连接)。
  6. 如果成功,将向用户显示注册到已验证电子邮件地址的用户帐户。

第二种方法可能还没有完全考虑清楚,但我认为它比简单地向用户发送电子邮件具有以下优点:

  • 您还有一个机会来验证用户确实控制了电子邮件地址,因为此时您可以验证 SPF 记录。
  • 您不太可能使用非法密码重置电子邮件打扰用户,因为攻击者必须在发送重置邮件之前通过 SPF 检查。
  • 重置邮件不太可能被垃圾邮件过滤器阻止,因为它是对用户发送的电子邮件的实际回复。