【问题标题】:How to phase out a password hashing algorithm in an existing web application?如何逐步淘汰现有 Web 应用程序中的密码哈希算法?
【发布时间】:2014-09-24 01:15:52
【问题描述】:

许多questions 在(网络)应用程序中使用asked 关于hashing 密码,但我遇到了不同的问题。我知道我目前正在处理的应用程序不够安全(只是 sha1 没有盐或任何东西),但很难改变它突然。

我必须找到一种方法来为所有 (± 50.000) 个用户实施一种新算法。我一直在考虑一些解决方案,但没有一个听起来是正确的。

1) 使用新密码向用户表添加第二列。每次用户通过身份验证时,我都会将密码与其新哈希一起存储并丢弃旧密码。这实际上意味着 sha1 需要数年时间才能逐步淘汰。

1.1) 执行上述操作,但会刺激用户重新登录我们的系统以进行安全更新,但这确实让人感觉承认存在(预)存在的安全漏洞。这不符合我的管理层的喜好。

2) 重新验证所有用户并丢弃所有密码。这是非常严谨的,对于用户来说也是一个痛点。

你会如何处理这个问题?

【问题讨论】:

    标签: security web-applications encryption password-protection


    【解决方案1】:

    您可以通过使用 sha1 哈希作为新改进哈希实现的输入来扩展现有解决方案,您可以在其中添加盐等。然后,新解决方案将包括 sha1 步骤 + 您可能想要的任何改进。

    通过这种方式,您可以从已有的哈希值中计算出新的哈希值,同时改进解决方案。

    【讨论】:

    • 我不知道为什么我没有想到这一点,但这真的很聪明。这样可以省去很多麻烦。谢谢!
    • 但它仍然会给您的哈希算法留下愚蠢的遗留问题。我建议将此作为现有散列的过渡措施,但对所有 new 散列采用更简洁的算法,以便您最终可以放弃旧的散列。
    • 据我了解,您建议将 pbkdf2( salt, sha1(passwd)) 存储在数据库中,然后切换 sha1 列。我认为这是个好主意。事实上,鉴于 heartbleed 漏洞,有人可能会争辩说,用户密码不应该直接在服务器端处理,而应该由客户端处理。在客户端执行 sha1 将是朝着正确方向迈出的一步(如果我们可以在客户端执行所有操作会更好,但这比我在这里解释的要复杂一些)。
    【解决方案2】:

    我会按照您首先建议的方式进行操作:每当用户进行身份验证时,存储新哈希并丢弃旧哈希。您不一定必须将新哈希放在单独的数据库列中;您可以改为添加一列,仅说明哈希的格式,并为实际哈希使用同一列,而不管其格式如何。

    您不必强制用户登录只需更新他们的密码哈希值,但将来可能会有其他事件(例如不相关的安全漏洞)提供重置密码或以其他方式让所有人登录的更好理由。

    一年后,任何仍保留旧格式密码哈希的人都是一年未登录的人。现在可能是向他们发送提醒电子邮件并最终删除未使用的帐户的好时机。

    【讨论】:

      【解决方案3】:

      每个密码存储系统都必须选择切换到更好的哈希算法,您的问题不是一次性迁移问题。良好的密码哈希算法(如 BCrypt 或 PBKDF2)有一个成本因素,有时您必须增加这个成本因素(因为更快的硬件),然后您需要与迁移所需的完全相同的过程。

      当今的密码库通常会生成一个包含所有参数(如盐和成本因子)的字符串。生成此格式的原因正是您可以切换到更安全的算法而不会丢失现有密码。验证程序知道使用什么算法进行验证,因此您可以看到这确实是一个“官方”的解决方案。

      $2y$10$nOUIs5kJ7naTuTFkBy1veuK0kSxUFXfuaOKdOKf9xYT0KKIGSJwFa
       |  |  |                     |
       |  |  |                     hash-value = K0kSxUFXfuaOKdOKf9xYT0KKIGSJwFa
       |  |  |
       |  |  salt = nOUIs5kJ7naTuTFkBy1veu
       |  |
       |  cost-factor = 10 = 2^10 iterations
       |
       hash-algorithm = 2y = BCrypt
      

      一般不需要重新设置密码,等到用户下次登录,你就有明文密码,可以计算出更安全的哈希值。如果现有的哈希非常弱,例如在您使用未加盐的 SHA-1 的情况下,那么您可以立即通过散列旧哈希来提供更多保护,这对于未加盐的哈希尤其容易。

      $hashToStoreInDb = new_hash($weakUnsaltedHashFromDb);
      

      为了验证,您可以:

      1. 首先尝试使用新算法验证输入的密码。
      2. 如果不匹配,与双哈希算法new_hash(old_hash($password))比较。
      3. 如果双哈希值匹配,则可以计算并存储更新的哈希。

      确保您首先检查最新算法,然后检查旧算法。那么只有下次用户登录时,登录时间才会更长,并且新用户不会受到向后兼容性问题的影响。当然你也可以利用上面的格式,将其标记为双哈希。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-06-30
        • 2011-10-10
        • 2016-01-15
        • 1970-01-01
        • 2023-03-02
        • 2012-05-24
        • 2013-08-16
        • 1970-01-01
        相关资源
        最近更新 更多