【问题标题】:Is it possible to figure out the key from the original and the encrypted string?是否可以从原始字符串和加密字符串中找出密钥?
【发布时间】:2019-02-02 21:20:14
【问题描述】:

编辑

我正在解决这个问题,因为我还没有一个决定性的答案(虽然一两个很接近)。我正在寻找的基本上是 yesno 答案以及一些信息来支持它。


我们有一个存储用户密码的系统,该系统由数据库中的通用系统密钥加密。如果具有 DB 访问权限的人持有该系统密钥,那可能是灾难性(显然)。

我们现在知道的正确方法(根据大多数(?))是将 PW 的加盐哈希存储在数据库中,但相对接近我们想要的版本最小化代码更改,因此认为防止有人从数据库中读取 PW 的一种非常简单的方法是简单地反转过程并切换参数。

也就是说,我们将使用用户密码作为密钥对每个系统(数百个)唯一的加盐字符串(每个加密添加随机尾部)进行加密,并将结果存储在数据库中。在 PW 验证时,我们将使用输入的 PW 对存储在 DB 中的字符串进行解密,并与系统密钥匹配以进行验证。

System key+random 加密,password 存储在 DB encrypted key

即用户密码永远不会被存储,并且在我们简单的头脑中是无法恢复的。

但作为加密领域的菜鸟,我们想知道在该领域有更多经验的人是否可以回答简单问题 -

能否从原始字符串和加密字符串中找出密钥?

我们认为这是一种出色 ;) 确保用户密码不被泄露的方法,但在网上找不到任何关于该方法的内容。这让我们不确定,因此询问了这个伟大的社区。​​p>

(并且蛮力不是一个充分的答案,因为(在这种情况下)无法避免。)

编辑:

我将在此处粘贴我的一个 cmets 以(希望)使一些事情更清楚:


@zaph 感谢您的意见,但我认为大多数人都忽略了这一点。几天后我们对即将发布的版本进行了代码冻结,我已经实现了我在问题中提到的方法。在下一个版本之前,我将阅读该主题并实现第三方库,如 scrypt 或类似的。我真的只需要知道是否有现有的可行算法来反转这个过程,从而使我的新实现比旧的加密密码方法更糟糕。

【问题讨论】:

  • 它是什么类型的数据库?如果是 MySQL,您应该在 甚至触及数据库之前加密数据(无论采用何种方法)。不要在数据库输入之前加密。
  • 再问:我怎么读到你所做的只是在经典加密过程中交换了值/密钥角色。
  • (And brute force is not a adequate answer, since that's (under the circumstances) is impossible to protect from.) 哦该死。好吧,考虑到您的个人资料泄露了您的公司,而您刚刚告诉我们您的密码系统使用了不良做法,并且您没有合适的暴力保护……拉起躺椅观看...
  • @Martin 这是 MSSQL。并且所有加密都是在数据库写入之前完成的。而且 - 是的,这样存储在数据库中的是我们的加密系统盐,而不是用户的 PW。
  • @ClasG 是的,建议的方法极易暴露大多数用户密码。您必须决定哪个更重要:代码冻结(任意)或用户的安全(绝对)。不是新方法比以前更好,而是新方法是否安全并使用当前经过验证的实践以有意义的方式保护您的用户。您处于这个可怕点的原因是因为直到最后一刻才解决安全问题。你会选择哪一个?

标签: database security encryption


【解决方案1】:

我们有一个存储用户密码的系统,该密码由数据库中的通用系统密钥加密。

这是一个非常糟糕的做法,因为密码可能是可逆的。根据我的经验 - 数据泄露只是时间问题......您可能会发生的灾难性场景将会成真。

我们现在知道的正确方法(根据大多数(?))是将密码的加盐哈希存储在数据库中,

今天最好的选择是使用“慢散列”,见https://security.stackexchange.com/questions/211/how-to-securely-hash-passwords/31846#31846

在密码验证时,我们将使用输入的密码解密存储在数据库中的字符串,并与系统密钥匹配进行验证。

这就是问题所在。一旦系统密钥被泄露(或被内部人员使用),所有密码都可能被泄露。使用散列更安全(代码差异不应该那么大)。

是否可以从原始字符串和加密字符串中找出密钥?

使用任何当前的现代密码,目前都无法根据明文和加密值的知识来计算/猜测加密密钥。

【讨论】:

  • 感谢您的回答。但是我觉得你的回答有点模棱两可。在您的第三部分中,您声明“一旦系统密钥被泄露(或被内部人员使用),所有密码都可能被泄露”。如果您对 实际 问题(第 4 部分)的回答是“目前不可能可能”,那又如何呢?系统密钥只是一个任意字符串,添加了系统唯一盐。
  • @ClasG :只有普通和加密的随机字符串,不可能派生加密密钥(直到有人没有发现所用密码的弱点)。 The system key is just an arbitrary string - 问题是有这样一个字符串,它可以被具有访问权限的人访问或计算......合法与否。
  • 嗯,就是这样。系统密钥不是那么秘密。也许您可以将其视为公钥(?)。事实上,它可以公开。没关系。重要的是,当使用 PW 作为密钥加密时,存储在 DB 中(这是第一次设置或更改 PW 时),然后(在登录时)我们用输入的密码解密存储的值,它应该与这个系统匹配密钥/“公钥”。你明白我的意思吗? (也许我的问题还不够清楚。)
  • @ClasG:正确的方法是 - 存储密码的加盐慢速哈希,当用户登录时,读取盐,创建所提供密码的加盐慢速散列并比较散列。要比较密码,您无需解密它们,只需比较哈希值即可。使用 PW 作为加密密钥通常不是最好的主意,它们具有低熵(短且不够随机)。为什么要强迫自己使用加密,而不是哈希?为此目的更好地散列它
【解决方案2】:

抱歉,按照大多数人的做法,使用 bcrypt 或 scrypt 之类的东西用盐对密码进行哈希处理。尝试使用一些知名、流行的库来使事情变得更快、更容易(如果您需要帮助,请评论寻找)。

是的,您所描述的内容听起来可能是安全的,但正如 @gusto2 所说,您没有足够的熵来进行安全加密,从而迫使您使用密钥派生方案。

使用密钥派生方案的唯一问题是密钥派生基本上是一种特殊的散列,在这种情况下,您应该选择第一个选项,并按照其他人所做的那样做。

【讨论】:

  • 像 PBKDF2 这样的密钥派生方案是当前的安全方法(NIST 批准)以及 bcrypt、scrypt 或更好的 Agron2i。这些方法应该消耗大约 100 毫秒的 CPU 时间和大量的内存,Agron2i 就是为了实现这一点而设计的。
  • @zaph 是的,尽管有些人更喜欢使用已经存在较长时间的散列算法。就个人而言,我更喜欢 scrypt 或 Argon2id(而不是 Argon2i)来进行密码散列。
【解决方案3】:

很抱歉在最后几个小时内参与了赏金活动,但我有一些重要的想法要贡献。

首先,我在这里没有看到对OWASP 的任何引用。他们可能是最大的软件安全社区,您应该经常查看他们的建议,不仅是为了密码保护,还包括任何其他安全主题。每年他们都会发布一份名为“OWASP Top 10”的文档,列出最常见的 Web 应用程序漏洞。

根据去年的 OWASP Top 10,您试图减轻的风险是列表中的第 3 号风险,称为“敏感数据暴露”。它不仅适用于密码,还适用于信用卡号等敏感数据。对于您的问题中描述的问题,我想强调第三个攻击场景示例:

场景 #3:密码数据库使用未加盐或简单的哈希值 存储每个人的密码。文件上传漏洞允许攻击者 检索密码数据库。所有未加盐的哈希都可以暴露 带有预先计算的散列的彩虹表。生成的哈希值 简单或快速的哈希函数可能会被 GPU 破解,即使它们 盐渍的。

为防止此类攻击(有时称为“彩虹攻击”),OWASP 的建议如下:

  1. 对应用程序处理、存储或传输的数据进行分类。根据隐私法、法规确定哪些数据是敏感数据 需求或业务需求。
  2. 根据分类应用控件。
  3. 不要不必要地存储敏感数据。尽快丢弃它或使用符合 PCI DSS 的标记化甚至截断。 未保留的数据不会被窃取。
  4. 确保对所有静态敏感数据进行加密。
  5. 确保采用最新且强大的标准算法、协议和密钥;使用适当的密钥管理。
  6. 使用安全协议加密传输中的所有数据,例如具有完美前向保密 (PFS) 密码的 TLS,密码优先级由 服务器和安全参数。使用指令强制加密 比如 HTTP 严格传输安全 (HSTS)。
  7. 对包含敏感数据的响应禁用缓存。
  8. 使用具有工作因子(延迟因子)的强自适应和加盐哈希函数存储密码,例如Argon2scryptbcrypt,或 PBKDF2
  9. 独立验证配置和设置的有效性。

它们都很重要,但是对于您的用例,请特别查看 #8 以及我在其中包含的链接。总之,您需要一个具有工作因子的强自适应和加盐散列函数

另外,不要忘记定期针对您的生产环境运行penetration tests (pen tests)。这非常重要。

如果您想开始测试/验证您的彩虹攻击防御,OWASP 提供了一个名为“OWASP Rainbow Maker”的工具。

OWASP Rainbow Maker 是一款旨在破解哈希签名的工具。它 允许测试人员插入哈希值和可能的关键字和值 应用程序可能使用它来创建它,然后它尝试了 多种组合以查找用于生成哈希的格式 价值。

希望对您有所帮助,如果您有任何问题,请向 cmets 射击。

【讨论】:

  • 感谢您的贡献。这对于即将发布的版本的实施非常有价值,我们将在此处考虑有价值的答案中所说的所有内容。谢谢!
  • 乐于助人。谢谢!
【解决方案4】:

根据要求:“来自可靠和/或官方来源的答案”——美国国家标准与技术研究院。

NIST Digital Identity Guidelines 第 15 页:... 验证者应以能够抵抗离线攻击的形式存储记忆的秘密。记忆的秘密应使用合适的单向密钥派生函数进行加盐和散列。密钥派生函数将密码、盐和成本因素作为输入,然后生成密码哈希。

salt 必须是加密安全的,并且对于每个密码都是唯一的,它可以(并且通常是)与散列密码一起保存。成本因素应在 1us 的 CPU 时间(未经过)的范围内。成本系数也可以与密码一起保存,因此可以在将来根据需要进行更新。

关键是让攻击者花费大量时间通过蛮力寻找密码。

其他具有类似属性的函数包括PBKDF2Rfc2898DeriveBytesArgon2ipassword_hashBcrypt

注释(从问题 cmets 移出):

回应:蛮力不是一个充分的答案,因为(在这种情况下)无法避免。
这正是必须并且可以防御的攻击类型。当前的最佳实践是要求每次尝试都是唯一且耗时的。因此随机加盐和迭代约 100 毫秒。因此,针对用户散列密码的试用密码的每次尝试都需要大量时间。在暗网中出售的攻击需要大量用户凭据,因此大多数密码必须被暴力破解才能获利。

回应:我真的只需要知道是否有现有可行的算法来反转这个过程,从而使我的新实现比旧的加密密码方法更糟糕。
是的,建议的方法极易暴露大多数用户密码。这不是比现有方法更好或更差的问题,而是使用当前做法保护用户凭据以保护用户和您的责任的问题。

对 OP 提出的解决方案的潜在攻击:
我之前发布了一个可能的简单攻击,这里又是:获取数据库和系统密钥进行验证。从frequent passwords 列表中选择一个条目并尝试使用系统密钥。这非常快,不到一微秒,因此大多数密码都会很快找到。一般攻击不需要找到所有密码,只需足够高的百分比,使用户信息 + 密码在Dark Web 上可售。

【讨论】:

    【解决方案5】:

    通过快速谷歌搜索,我找到了Stack Exchange thread

    尝试根据明文和密文找出密钥称为Known-plaintext attack。大多数加密算法都不容易受到这种攻击。

    【讨论】:

    • 哇!你是第一个直接回答我问题的人。一个很好的答案(正是我想听到的;)。谢谢!
    • 这是不正确的,这不是针对随机加密密钥的纯文本攻击。这是一种来自常用密码列表的密码攻击,很有可能找到密钥,并且加密数据的长度仅为两个块中的一个,与已知数据(系统密钥)相比。缺少的一个主要组成部分是任何工作因素,请参阅 Fabio Manzano 的答案。由于这种保险密码验证系统,该方案可能会使 OP 服务的用户面临风险。
    • 未来的读者:知道这种方法不安全,并且不遵循 NIST 或 OWASP 的建议。
    • @zaph 我不知道您是否没有阅读我在 Q 和 cmets 中所写的内容 - 这是一个 临时 解决方案以改进当前 非常在数据库中有加密密码的糟糕解决方案。这个新的解决方案更加更加安全,并且根据我在 Mathew 和其他人在答案和 cmets 中贡献的链接中读到的内容,它安全的,因为您无法提取密钥。是的,缺少慢速哈希 可能使用蛮力,但这将在下一个版本中修复。我重视所有告诉我如何做到这一点的贡献者。谢谢大家!
    • @SamWhan 您在押注等待下一个版本的攻击者——祝您的用户好运。 “更安全”,但仍然比当前做法的安全性低 10,000 多倍。我们目前有一个巨大的安全问题,这是为什么(安全性差)和如何(由故意提供低安全性的开发人员)的一个例子。您是否告诉您的用户密码不安全,但将在下一个版本中使用?
    【解决方案6】:

    我认为 gusto2 有点 OTT,虽然它比您尝试替换的主密码解决方案更好,但它仍然远远不能接受。

    或多或少是crypt works in DES mode。但是,在您的实现中,每个用户不使用唯一的盐,当 2 个用户具有相同的密码时会很明显(为散列切换可逆加密并不能缓解这种情况)。您可能正在使用具有更多位的更好算法,但您的实现落后于 40 年前的技术。

    【讨论】:

    • 已编辑 Q. 我们确实在加密时将随机数据添加到系统 salt 中,因此两个相同的 PW 将被不同地加密。但是感谢您将我指向 DES 文章。这很有趣,我会进一步调查。
    • No gusto2 不是 OTT,这是当前保护密码的方法。使用 CPU 使用率约为 100 毫秒的密码散列或密钥派生方法。
    【解决方案7】:

    正如其他用户所建议的那样,您不应在数据库中存储可解密的密码,因为如果密钥泄露(或管理不善,被您组织中的任何人用于欺诈目的),可能会造成灾难性的后果。

    作为一种安全标准方法,passwords should NEVER be retrievable by the database,通过主密钥密码恢复方法。如果攻击者要获得对应用程序源或数据库的访问权限,他们仍然很难窃取用户的身份,因为他们不可能找回用户的密码。

    因此,您的方法可以为每个用户使用您的 per system (hundreds of them) unique salted string (with a per encryption added random tail),将其存储在数据库中,并使用用户的密码输入作为哈希盐(而不是您建议的密钥) .这种方法和你的不同之处在于你不会解密存储的哈希,而是将用户输入生成的哈希与存储的哈希进行比较。

    Here'sother resourcespassword management 上的一些other resources,您可以阅读以确保用户的隐私。

    【讨论】:

    • 感谢您的意见。但正如我所说,我们已经计划很快实施一种处理密码的新技术。这个问题的目的是找出我的新实现是否让事情变得更糟,或者我现在确信它会变得更好。 (但这显然没有通过,因为只有一个答案涉及回答它。)但是,在规划新功能时,我们一定会使用您的答案作为输入。再次感谢。
    猜你喜欢
    • 2021-07-07
    • 1970-01-01
    • 2012-06-14
    • 2011-04-07
    • 2020-10-30
    • 2014-12-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多