【问题标题】:How to handle salts that can't be random? A deterministic salting strategy如何处理不能随机的盐?确定性加盐策略
【发布时间】:2018-11-09 16:29:42
【问题描述】:

考虑以下场景:

  • 用户在网站上输入唯一代码(比如礼品卡)。
  • 代码对应于数据库中必须检索的对象。
  • 代码是机密,不能以纯文本形式存储。
  • 相反,代码将被散列并存储在数据库中。哈希算法将是 sha-512 或 bcrypt 结合一些加盐策略。

为了查找代码,必须对用户输入的代码进行哈希处理。通常,在密码认证的情况下,用户的身份是已知的,因此可以在计算哈希之前从数据库中检索盐。在上述场景中,虽然无法加载与代码关联的盐,因为我们不知道代码对应于数据库中的哪个对象。这似乎意味着对于这种盐可以是随机的方案没有这样的加盐策略。

我想就以下想法提供意见:

我们可以对用户输入的代码进行散列(比如 sha2)作为盐吗?

salt = sha2(code)
hashedCode = hash(code + salt)

如果存在上述漏洞,是否可以在哈希中包含一些额外的全局机密有助于降低风险?

salt = sha2(code + globalSecret)
hashedCode = hash(code + salt)

谢谢!

【问题讨论】:

    标签: security hash architecture salt deterministic


    【解决方案1】:

    散列是绝对错误的方法。我会在几秒钟内解决这个问题,但首先让我解决数据库中的查找问题。

    在数据库问题中查找秘密

    大多数礼品卡正面都有代码,背面有刮刮秘密的原因解决了这个问题。

    用户在前面输入代码。然后您的应用程序会提取数据库记录。然后用户在背面输入刮擦代码。您可以将该代码与数据库中的代码进行比较。

    另一种方法是拆分代码,因此第一部分是数据库记录 ID,第二部分是要比较的代码。例如:

    1234 5511 2121 1234 --- 12345511是记录ID,21211234是密码。


    散列是错误的方法

    所有这些都与关于散列的问题无关。我们建议您使用哈希密码,因为我们不希望有人获得数据库并反转密码,然后将这些密码用于其他网站。

    在您的场景中,您最终可能会处于有人窃取您的数据库,然后能够猜出所有代码的状态。好吧,这是您的解决方案的问题。如果我知道代码在 1 到 100000000 之间,那么我可以枚举 1 到 100000000,计算每个代码的哈希/bcrypt,并恢复所有代码。我可以在几分钟内做到这一点。除非您发送 2^128 长度的代码(我永远不会输入),否则该解决方案是完全有缺陷的。

    当然,这就是它们具有盐值的原因。所以我必须去每个giftcode哈希,并遍历所有10000000个值。但这仍然是几个小时的工作,而不是你想要的几年。盐根本不能解决问题。


    那这件事情怎么办呢?

    如果您的风险是有人窃取数据库,然后使用所有礼品代码窃取金钱,则会发生以下两种情况之一。您要么取消所有代码(然后一堆拿着礼品卡的人会生气),要么保护代码。

    您希望使用 HMAC,而不是将代码存储为纯文本或散列代码(基本上是纯文本,因为我可以在几分钟内枚举所有可能的值)。 HMAC 是一个哈希和一个密钥。

    giftcode_in_db = HMAC(<SECRETKEY>, giftcode_from_user)

    现在,要保护您的所有礼品代码,您只需保护密钥即可。仅在内存中使用,并让操作员手动输入或使用 Hashicorp Vault 进行实际的 HMAC 操作。

    如果有人窃取了您的数据库,他们也需要窃取密钥。如果有人窃取了密钥,他们也需要窃取数据库。

    【讨论】:

    • 让我们考虑一下有人窃取数据库的场景。使用 Hmac 是什么阻止某人计算 HMAC 以枚举 和礼品代码的可能值?这与在盐渍策略中使用该 SECRETKEY 作为辣椒有何不同?我知道一些差异,例如hmac("code1", "secret") != hmac("code", "1secret")sha("code1" + "secret") == sha("code" + "1secret")。还有其他原因导致这些不同吗?
    • 我还应该提到代码可能是 16 个字母数字字符长。
    • 非常相似。 Salt作为一个概念是一个以明文形式存储的值。密钥必须是秘密的。对数据库的实际攻击(如 sql 注入或丢失备份)不会包含数据的密钥。 Hmac 也有一些额外的步骤来保护密钥的秘密。
    【解决方案2】:

    如果您的 16 个字符的字母数字代码 (0-9 a-z A-Z) 是真正随机生成的,那么即使使用 SHA-256 之类的快速哈希算法,它们也足够强大,可以在不加盐的情况下进行哈希和存储。

    可以提高使用服务器端密钥的安全性,无论是加密哈希还是使用 HMAC 都不是那么重要。重要的是,攻击者需要在服务器上获得额外的权限才能获取密钥,然后才能开始破解(SQL 注入是不够的)。

    如果代码较弱(较短),您还可以使用键拉伸,以增加暴力破解所需的时间。只要代码不是太短,即使是几毫秒的单个计算也可以阻止暴力攻击。键拉伸可以独立于加盐完成。更好的当然是使用足够强大的代码。

    【讨论】:

    • 感谢您的解释。假设可能存在需要较短代码的情况(可能在用户上传较短的现有代码的情况下。它们甚至可能只是数字)。我们将使用不会存储在数据库中的hashingSecret。您能否提供有关使用 HmacSHA512(code, hashingSecret)SHA512(code+hashingSecret) 的任何见解?我对是否需要 Hmac 有点困惑,因为我们不需要验证哈希的真实性。我们纯粹在内部使用它来进行查找。
    • @TimJ - 您应该知道,服务器端密钥只会增加一点优势,一旦攻击者获得服务器权限,就没有什么可以阻止他成功地暴力破解代码,但是计算单个哈希的必要时间。因此,对于短代码,键拉伸变得更加重要(例如 PBKDF2)。我建议不要在 HMAC 中使用密钥或作为胡椒粉,而是对哈希值(例如 AES)进行加密,这样可以在必要时更改密钥。
    • @TimJ - 无法正确保护短数字代码,它们太容易暴力破解。
    猜你喜欢
    • 2012-08-16
    • 2016-07-08
    • 1970-01-01
    • 2015-03-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-05
    相关资源
    最近更新 更多