【问题标题】:Safe way to store decryptable passwords in ruby在 ruby​​ 中存储可解密密码的安全方法
【发布时间】:2015-01-09 06:36:10
【问题描述】:

我想以安全的方式将一些密钥以加密形式存储在数据库中。同时,我需要在代码中的某处使用密钥的非加密(原始)形式。我计划使用 PBKDF2 进行密码散列 PBKDF2。是否可以使用 PBKDF2 以加密形式解密存储在数据库中的密钥。或者是否有任何简单而安全的程序可用?

【问题讨论】:

  • 安全且可解密的密码是矛盾的。如果它们是可解密的,则它们是不安全的。如果您的程序可以以纯格式获取它们,那么您的密码存储有多安全并不重要。 (不,您无法解密 PBKDF2 生成的派生密钥。)

标签: ruby-on-rails ruby ruby-on-rails-4 encryption


【解决方案1】:

密码和密钥通常以散列形式存储。这意味着它们在保存到数据库之前通过哈希函数进行处理。像 bcrypt 这样好的散列函数具有以下属性:

  • 它为相同的输入产生相同的输出
  • 它为不同的输入产生非常不同的输出
  • 它的输出与随机的无法区分
  • 它是不可逆的

最后一个属性有一个非常重要的安全含义:当有人访问数据库时,他们无法恢复原始密钥,因为哈希函数是不可逆的,尤其是当哈希被加盐以防止攻击者使用彩虹表时。

这意味着如果您想稍后恢复密钥,您必须以加密(不是散列)形式保存它们。加密函数具有类似于散列函数的属性,关键区别在于它实际上是可逆的。对于此解密步骤,您需要一个密钥,该密钥需要存储在某个地方。

您可以将密钥存储在您的应用程序配置中,但这意味着如果有人获得对您服务器的访问权限,他们将能够检索加密密钥并解密所有存储的密钥。

我建议另一种方法,即用户只允许检索他们自己存储的密钥。它基于这样的想法,即使用只有用户知道的用户特定密码对密钥进行加密。每当您需要执行需要存储或检索密钥的操作时,系统都会提示用户输入密码。这样,您自己和攻击者都无法检索它们,但如果用户通过输入密码允许您的程序可以访问它们。

  • 在数据库中存储一个传统的散列用户密码,例如使用 bcrypt
  • 允许用户使用以下过程存储附加密码:
    • 提示输入用户密码和要存储的密钥
    • 哈希密码并与数据库进行比较以进行身份​​验证
    • 为每个输入的键生成盐
    • 使用用户输入的密码和盐来加密密钥以存储例如使用 AES 加密
    • 在数据库中存储盐和加密密钥
  • 要在需要以纯文本形式存储的密钥的操作中检索存储的密钥:
    • 提示输入用户密码
    • 哈希密码并与数据库进行比较以进行身份​​验证
    • 从数据库中检索加密密钥和盐
    • 使用用户密码和 salt 解密存储的密钥

小心从应用程序日志中删除用户提交的密码;-)

【讨论】:

    【解决方案2】:

    密码永远不会以人们事后可以解密的任何方式存储在数据库中。无法保证有人不会破解您的数据库表并窃取您存储的所有内容。

    如果您为每个用户存储一个加密(散列)密码,即使您的数据库被黑客入侵,那些窃取您的解密密码的人也会花费大量时间来找出实际密码。他们总是可以使用您的相同加密并比较常见密码的结果哈希值。例如,他们可以加密“MyPassword123”,然后将该散列密码与数据库中的每个密码进行比较。使用这种模式仍然可以猜出弱密码。

    因此,即使是不可解密的密码也有其弱点,但如果您允许某人解密您存储的内容,那么他​​们基本上很容易获得您用户的每一个密码。非常糟糕的做法。一些最大和最“安全”的公司的存储密码哈希被盗,因此您不能假设自己不会成为受害者。

    【讨论】:

    • 仅使用散列函数是不够的,仅添加盐对提高安全性无济于事。相反,iIterate over an HMAC with a random salt for about 100ms duration and save the salt with the hash.使用PBKDF2password_hashBcrypt等函数和类似函数。关键是让攻击者花费大量时间通过蛮力寻找密码。保护您的用户很重要,请使用安全的密码方法。
    • 1.散列是不是加密,它们是完全不同的东西。 2. 使用频繁的密码列表和现成的黑客软件,暴力破解散列密码很容易快速获得 90%。 3. 攻击者不需要“你用户的每一个密码”,他们只需要最多,也许在暗网上出售。
    【解决方案3】:

    我在使用 Ruby 的 bcrypt 中遇到了同样的问题,它适用于用户验证,因为它比较了用户输入的明文和散列密码之间的差异,而散列密码永远不会解密为明文。我发现可以解决您的问题的宝石之一是 encryptor,它使用几个不同的密钥进行加密。因此,您可以将密码保存在数据库中,同时将密钥安全地保存在另一个位置(存储中的文件)。

    更多信息可以在rubygems page找到。

    【讨论】:

    • 不要加密密码,当攻击者得到数据库时,他也会得到加密密钥。使用随机盐在 HMAC 上迭代大约 100 毫秒,然后将盐与哈希一起保存。使用 password_hash、PBKDF2、Bcrypt 等函数和类似函数。关键是让攻击者花费大量时间通过蛮力寻找密码。
    • 这个想法不是将密钥保存在数据库中,而是在一个单独的文件位置说只能由服务帐户和少数系统管理员访问。 Bcrypt 和 PBKDF2 似乎只解决了密码验证的一个特定问题,但是当您需要自动脚本的明文密码时,它并不能解决问题。
    • 如果需要明确的密码,比如传递给另一个应用程序,更好的概念是使用单独的加密服务器,这样加密密钥不在数据库服务器上,而是在另一个最小的非常安全的服务器上,看到这个SO answer
    • 那么这与我提到的方法有什么不同呢?我不赞成将密钥保存在数据库或数据库服务器上,而是一个完全独立的位置,只能由服务帐户访问。也许我最初的答案不太清楚。
    • 获得对 Internet 连接服务器的管理员访问权限的攻击者可以访问单独的文件位置,这是一种常见的攻击媒介。没有连接到 Internet 的单独加密服务器具有非常有限的管理员帐户和两因素身份验证更安全。无法从面向 Internet 的服务器访问加密密钥。此外,加密服务器请求应该受到速率限制,并且应该警告速率违规。在实践中它接近于 HSM。但是,请务必考虑使用 HSM 进行密码密钥处理和密码加密/解密。
    【解决方案4】:

    这个问题的最新答案:

    1. 如果您使用 Rails Lockbox
    2. 如果你使用 Rails >=7,encryption is now built inActiveRecord

    【讨论】:

      猜你喜欢
      • 2011-02-03
      • 1970-01-01
      • 2010-09-16
      • 2013-01-18
      • 1970-01-01
      • 1970-01-01
      • 2011-08-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多