底层方法更改时是否应自动重置密码

信息安全 密码管理 用户管理
2021-09-01 03:34:36

我目前是处于开发阶段的项目的工程师。该项目的一个“模块”提供了用户身份验证/授权的能力。然而,我们担心密码散列算法可能不符合 cop(也不是 BCrypt)。(可怕的是不太确定它是什么以及它来自哪里!)。

这显然必须改变,并且正在安排补丁。我们必须自然地更新所有测试用户,因为他们的密码将使用旧的哈希方法,这不是什么大问题,我们所有的演示用户在构建时都是自动化的,所以它正在更新脚本。但下一个问题是,如果这是一个拥有活跃用户和过时用户的生产系统,无论数量如何。什么是最佳实践。

  1. 自动强制每个用户重置密码?这将通知每个用户他们的密码已被更改,并可能导致问题/困惑,并可能导致怀疑存在安全漏洞。可能会提出更多问题,这些问题不一定能够由网站利益相关者回答。
  2. 更新数据库以标记它是新方法还是旧方法,然后一旦用户通过身份验证,请使用更新他们在数据库中的密码。在服务中需要一些逻辑,并且转换对于任何现有用户来说都是无缝的。问题是如果存在漏洞,那么很明显这里有两种方法,如果发现不太安全的方法不安全,那么它显然可能会被破坏。
  3. 使用现有哈希的 BCrypted 版本重置所有密码。将其标记为旧样式,因此在成功验证后,它只保留密码的散列而不是散列的散列。
4个回答

您的选项 1. 是个坏主意:除了您陈述的用户体验/公共关系原因之外,您还为攻击者提供了一个窗口来拦截密码重置令牌并破坏您服务器上的每个帐户。如果您甚至有一个用户懒得登录/更新他们的密码,它也不能解决您的问题。

乍一看,我觉得 2. 和 3. 都不错。您的#2 的安全性不亚于您现在正在做的事情,但是 2. 意味着您必须永远继续支持当前的弱登录(或执行类似“X 个月后我们正在擦除您的密码并强迫您这样做)恢复”,它破坏了你想要的良好的用户透明度,所以让我们忽略它)。

让我们考虑一下您在数据库中有永远不会再次登录的用户的情况。使用 2. 和 3. 您必须永远继续支持代码库中的当前哈希算法,以防万一他们登录,但至少 3. 具有他们(或者更确切地说,您)受到保护的优势如果您的数据库被盗,则进行离线暴力攻击。

由于您必须永远保留“旧样式标志”列,请帮自己一个忙,并使其成为intbool如此,这样如果您必须再次更新密码哈希算法,您可以记录它们使用的旧样式.


更新:这里提出了一个非常相似的问题,并建立在这个线程的讨论之上。

如果您可以执行选项 3,我不明白您为什么会考虑其他选项。这是迄今为止最好的选择。有了这个选项,我的直觉是考虑使用两种不同的盐,一种用于旧算法,一种用于带有 bcrypt 的新算法。我正在设想这样的设置:

  1. 如果您从今天开始,设置您的新密码系统。
  2. 创建一个新的单独表,其中包含用户名(或 id)、散列算法(名称或 id)、salt 字段。
  3. 登录时,检查用户在单独的表中是否有记录,如果有,则以旧方式对密码进行哈希处理,然后以新方式对结果进行哈希处理并与 bcrypt 哈希值进行比较。如果匹配,则以新的方式对密码重新加盐/哈希,并从单独的表中删除记录。

缺点是您必须将密码在内存中保留几毫秒(谁在乎),并且您将在每次登录时进行额外的表查找,几乎永远,直到单独的表为空或直到旧帐户成为足够陈旧以至于您愿意要求他们自己重置密码。

请注意,如果您的旧方案使用盐进行哈希处理,您将无法使用方案#3,除非您单独存储盐。

通常盐与散列一起存储,并且您使用盐作为散列函数的输入 - 如果您不使用完全相同的盐,您将获得完全不同的输出。

如果你使用newhash(oldsalt+oldhash, newsalt),那么即使密码正确,你也无法重新创建oldhash(因为你没有oldsalt),也无法生成最终的hash。同样的事情适用于任何有参数的东西(例如 bcrypt 有一个“成本”参数 - 这需要在加密时设置,并嵌入到输出中,以在验证密码时使用)。

:正如其他人所提到的,如果您要存储哈希是“旧”或“新”样式,请考虑存储“方案”——例如,0 是“旧”,1 是 bcrypt(注意 I不要使用“新”——它现在是“新”,不会永远是“新”!)。一种常见的方法是在哈希的开头有一个标记(这可能已经是这种情况了!)。bcrypt 使用以下标准前缀之一:“$2a$”、“$2b$”、“$2x”或“$2y$”。根据您的“旧”算法的可能输出,您可能需要编写自己的前缀来标记这些,或者您可能能够摆脱“任何不以'$'开头的都是旧算法。

最后,由于您显然关心(正确的!)旧密码的安全性,我建议通过电子邮件向他们发送带有令牌的说明来强制每个人更改密码(不要!发送链接!你不想要你的用户点击一个链接!告诉他们登录到通常的地方)。然后,询问令牌和他们的密码。否则,过去曾窃取过密码的人可以更改密码,并获得有效的“新”密码。

最后:有一个到期日期 - 如果在此日期之前没有更改密码,那么它们应该失效。这个日期应该在电子邮件中,并且在未来不会太远(一周?取决于您的客户需要多长时间才能回复)。之后,他们将不得不通过“密码重置”程序。

我不知道你的密码编码方案是什么,但如果不是太糟糕,很可能是新旧格式的密码结构不同。

当系统从传统的密码编码更改为更安全的密码编码时,我已经在旧的 BSD 系统中看到过类似的情况。新密码以旧方案中不存在的字符序列开头,因此每次使用旧密码的用户登录时,都会使用旧方法验证其明文密码,然后默默地重新散列并存储回密码数据库中新方法。一个月后,数据库中没有旧密码,最终用户没有注意到任何事情。

那将介于您的第二种和第三种方法之间。

我知道在一个真正的生产网络系统中,现在情况可能会更糟,因为用户可能要等待数周甚至数月才能再次连接。但是(取决于实际活动)可以通过以下事实来缓解这种情况:几个月未连接的用户可能忘记了密码 - 或者您可以告诉他他忘记了...在这里可能更长 3 或 6 个月,在那之后我会将所有旧式密码重置为禁止值,迫使用户在下次连接时重置他的密码......通过忘记密码屏幕。

这里的好处是:

  • 对普通用户透明
  • 没有数据库架构更改 - 提供密码字段可以接受两种样式
  • 偶尔的用户将被视为几个月后忘记密码而不使用密码

缺点是它迫使您同时实现两种身份验证方法+所有样式密码的自动更新。