【问题标题】:System.Web.Helpers HashPassword Salt and Iterations?System.Web.Helpers HashPassword 加盐和迭代?
【发布时间】:2014-02-27 05:43:26
【问题描述】:

ASP.net 有一个System.Web.Helpers.Crypto 类用于散列和验证密码。它似乎动态生成盐并将其存储为密码哈希的一部分。

我的问题是,随着计算机变得越来越强大并且需要增加迭代次数以帮助防止暴力攻击,您如何增加现有密码的迭代次数?

迭代次数被硬编码到帮助程序中。将其更改为更大的数字将增加新密码的迭代次数,但在验证密码时也会单方面增加所有密码的迭代次数。这不会破坏旧密码的密码验证吗?

为了规划未来,您不想存储盐和迭代次数吗?

另外,是否可以通过执行额外的迭代来“加强”现有的密码哈希,或者迭代是否都必须作为一个操作发生?

【问题讨论】:

    标签: c# asp.net passwords cryptography


    【解决方案1】:
    1. 不,您不能“加强”现有密码 - 更改哈希迭代次数会破坏现有验证。除非您想强制所有当前用户创建新密码,否则不要更改哈希设置。如果您要加密而不是散列,这将是可能的(但不要进行加密)。

    2. 我们使用一个通用的辅助库进行加盐和散列,让我们可以调整每个项目的散列迭代次数,因此我们可以任意增加迭代次数。如果您担心面向未来,这可能会让您在未来扩大规模。

    通常我们使用算法组合(SHA256、MD5 等)加盐然后散列大约 100 次。迭代次数和哈希序列是各个项目设置的一部分 - 我们不会将其与盐和哈希结果一起存储在数据库中。


    编辑:

    现在我突然想到,(通常)您实际上可以对现有密码哈希进行多次哈希,以使它们与更新的哈希功能同步 - 只要您的新哈希例程的第一部分与您现有的相同。例如,如果您当前散列 10 次并将其更改为 100 次,则可以再散列现有值 90 次并更新数据库。如果Crypto 的实现过程没有加盐,我预计 10 + 90 次迭代哈希会产生与 100 次哈希相同的结果。

    但是,如果您搞砸了该过程,最终可能会破坏所有用户的现有密码。除非我真的需要,否则我不愿意实现这样的东西。

    【讨论】:

    【解决方案2】:

    你说得对,存储盐和迭代计数对未来的规划更好,看看 PHP 的password_verify()

    不仅迭代计数(称为成本,不完全是迭代计数,而是基于相同的概念)和盐与派生密钥一起存储,算法也被存储以防将来需要替换算法。

    System.Web.Helpers.Crypto 类使用 PBKDF2 对密码进行哈希处理,它在内部使用哈希算法在定义的迭代次数上对密码进行哈希处理。由于内部操作都是不可逆的,并且“迭代”段不是最终段,因此执行额外的散列不起作用。整个密码需要从其原始明文源重新散列。

    一般来说,在用户下次再次登录时会发生重新散列密码的过程。此时,系统可以确定用户的密码是否需要重新散列,并在需要时进行相应的操作。这不仅避免了运行可能导致停机的主要重新散列操作的成本,而且它是唯一一次用户的明文密码再次可用。如果在不久的将来可能存在漏洞,则应重新加密密码,而不是在漏洞完全暴露的时候,因为那时可能为时已晚。

    如果数据的安全性以及对未来的规划是一个问题,我建议您使用另一个类(也许自己制作),它允许自定义迭代次数并将所有相关数据存储在派生键/散列中密码本身。

    【讨论】:

    • 登录时重新散列的好主意!
    【解决方案3】:

    该帮助程序实际上存储了一个前缀,指示所使用的算法和迭代次数,因此如果将来算法发生变化,仍然可以验证旧密码。

    我们考虑将默认值从 1,000 提高到更高的值。然而,当我们这样做时,新的 CPU 命中率是不可接受的。消费者设备需要 1,000,000 次迭代是可以的,因为您不会真正关心您的平板电脑或手机是否需要 0.5 秒才能登录。但是当网页需要大量时间来处理登录请求时......好吧......您不希望用户仅通过登录来拒绝服务器。:)

    不幸的是,1000 次迭代仍然是提供更高安全性(通过直接盐和哈希)和保持 Web 服务器响应的最佳折衷方案。

    【讨论】:

    • Levi,在查看代码时,我找不到存储前缀的位置,该前缀包含有关混搭方法或迭代次数的信息。 HashPassword 和 VerifyHashedPassword 方法中的迭代次数似乎都是硬编码的。我们是在谈论同一个库,还是我没有看到更新的版本?或者那是 Salt 和/或 Subkey 的一部分?
    • @Sam 如果您查看班级的 cmets。您将看到已输入代码以将密码保存为“版本 0”。其中将规范定义为:PBKDF2 with HMAC-SHA1, 128-bit salt, 256-bit subkey, 1000 iterations。我假设如果您创建了更多“版本”,您可能会稍微修改代码以适应不同版本的密码(以及不同的迭代次数)。版本号简单地保存为派生密钥/密码的第一个字节处的单个字节(版本 0 的版本字节为 0x00)。
    • @CPUTerminator - 谢谢,我现在看到开头的多余字节了。
    猜你喜欢
    • 1970-01-01
    • 2013-12-22
    • 2016-10-31
    • 1970-01-01
    • 2011-02-27
    • 1970-01-01
    • 2015-02-17
    • 2016-03-01
    • 1970-01-01
    相关资源
    最近更新 更多