【问题标题】:Derive salt from password - How (in)secure is it?从密码中派生盐 - 它的安全性如何?
【发布时间】:2019-08-01 00:22:46
【问题描述】:

我遇到了以下问题: 在 Java 应用程序中,我想将一些配置数据存储在加密的本地文件中。此文件可能用于机密数据,例如用户凭据。

该文件应该可以通过使用密码(并且只能使用密码)访问。 现在大多数值得信赖的人和参考实现都使用随机盐。我完全理解这是一个合理的选择。但是,如果我的应用程序终止并稍后启动,则随机盐不再可用。此应用程序是独立的,因此不能将额外的数据库用作盐存储。

对于我的软件,用户只需输入密码(意味着:没有用户名、没有盐、没有最喜欢的动物或颜色)。

现在我的想法是从密码中提取盐值(例如,通过使用 SHA-256 的前 16 个字节)。

我的问题是:

  • 此实施的安全性如何?
  • 什么是仅使用密码加密内容的常用方法,并且是更好的选择?

这个问题的目的不是什么:

  • 盐的存放地点
  • 安全算法和加密实现(当然,加密不是我自己实现的)
  • 架构改进(不,我不想要一个全局数据库来存储东西)

【问题讨论】:

  • 通常在每次应用启动时都不会随机生成一个盐值,它们大多是硬编码的。
  • 得到了一篇由专家撰写的文章(不幸的是只有德语),上面写着“开发人员应为每次使用随机创建盐,以避免彩虹表攻击。与将盐与密码哈希一起存储在用户数据库、硬编码的常量盐可以通过反编译轻松读取。” (heise.de/developer/artikel/…)
  • 盐用于散列,而不是加密。
  • 盐用于单向哈希,而不是双向加密。通过从密码中提取盐,您不一定会使事情变得更糟,但也不会使它们更安全。例如,它不能防止彩虹表攻击。我 发现有点担心的是你想出了你自己的加密方案。如果我是你,我会找到一个加密库并阅读它的文档以了解如何有效地使用它。
  • @f1sh "通常情况下,每次应用程序启动时都不会随机生成 salt 值,它们大多是硬编码的。" - 不要这样做。这破坏了加盐的全部意义。对于每个密码,应该生成一个单独的盐。

标签: security encryption salt


【解决方案1】:

要加密数据,需要密钥而不是密码。有key-derivation-functions可以从用户密码中获取key。

盐可以用于密码散列,但不能用于加密数据。加密也有类似的概念,其中的随机值称为 IV 或 Nonce,并与加密数据一起存储。

你能做的最好的事情是

  1. 使用带盐的密钥派生函数,从密码中获取密钥。
  2. 您可以使用生成的密钥对数据进行加密。
  3. 在这种情况下,盐可以存储在加密数据容器中(IV 已经存在),因此不需要全局数据库。

回答您最初的问题:从密码中派生盐否定了盐的全部目的,它只是变成了一个更复杂的哈希函数。

【讨论】:

    【解决方案2】:

    首先,如果您能提供帮助,我强烈建议不要设计新颖的加密格式。正确地执行它们是非常困难的。如果您想要一种符合您所描述的加密格式,请参阅JNCryptor,它是RNCryptor 格式的实现。 RNCryptor 格式正是为这个问题而设计的,因此该规范是一个很好的信息来源,如果您不想直接使用它,您可以如何创建自己的格式。 (我是 RNCryptor 的作者。)

    另见libsodium。由于各种技术原因,它是比 RNCryptor 更好的加密格式,但正确安装和使用有点困难。 libsodium 有 several Java bindings

    当您说“当然,我没有自己实现加密”时,这就是您正在做的事情。加密方案不仅仅是 AES 代码。决定如何以一种新颖的方式生成盐就是实现加密。有很多方法可以以简单的方式将安全原语(如盐)组合在一起并使它们非常不安全。这就是为什么你想使用一些成熟的东西。

    关键在于您将盐与数据一起存储。我知道你说这不是储存盐,但你就是这样做的。最简单的方法是将盐粘在密文的开头并存储。然后你只需从标题中读取盐。同样,如果这样更方便,您可以将整个东西放在信封中。像 JSON 这样简单的东西:

    { "salt": "<base64-salt>",
      "data": "<base64-data>" }
    

    这不是存储数据的最有效方式,但它简单、标准且安全。

    请记住,盐不是秘密。人人都能读盐就好了。


    好的,关于如何正确地做到这一点已经足够了。让我们来回答您的实际问题。

    您的加盐建议不是盐。这只是一个稍微不同的哈希函数。加盐的要点是,如果两次使用相同的密码(不打算使用相同的密码),那么它们将具有不同的哈希值。你的计划失败了。如果我采用与您相同的方法,并且选择与您相同的密码,那么哈希值将是相同的。彩虹桌获胜。

    解决这个问题的方法是使用静态盐,而不是修改后的哈希函数。您应该选择代表您的系统的盐。我通常喜欢反向 DNS,因为它会导致唯一性。例如:“com.example.mygreatapp”。其他人自然会选择“org.example.ourawesomedb”。你也可以选择一个很长的随机字符串,但重要的是唯一性,所以我喜欢反向 DNS。 (随机字符串往往让人认为盐是秘密,而盐不是秘密。)

    这就是整个系统;只需选择一些恒定的盐,对您的系统来说是独一无二的。 (如果您有用户名,则将用户名添加到盐中。这是构造确定性盐的标准方法。)

    但对于文件存储,我永远不会那样做。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-07-05
      • 2016-07-28
      • 2011-12-29
      • 2016-04-01
      • 2013-08-23
      • 2016-04-06
      • 1970-01-01
      相关资源
      最近更新 更多