5

我提前为即将到来的Wall-O-Text道歉。这是(至少,对我来说)一个相当复杂的问题,我已经考虑了很多。如果你愿意的话,你可以阅读我的问题,也可以在这个 GitHub Gist 上看到一个用 Ruby 编写的测试实现(非常仓促,没有数据库支持,而且可能非常丑陋) 。


介绍

想象一下,需要创建一个基于 Web 的密码管理系统(通过 SSL!:) 具有以下要求:

  1. 个人用户使用他们自己的唯一密码短语登录系统。
  2. 这个密码短语应该足以让用户有效地使用系统(例如,通过智能手机等)——关键是他们不应该随身携带密钥文件。
  3. 用户可以在系统中存储任意长度的数据位(“条目”)。
  4. 条目在数据库中以这样一种方式加密,即数据库或应用程序中没有足够的信息来读取加密的条目。
  5. 用户应该能够与系统的其他用户“共享”条目,以便其他用户可以阅读条目的内容。

我不是密码学专家。想了一会儿,我想到了以下几点。 我的问题是:这个实现安全吗?我错过了什么吗?如果是这样,上述规范甚至可以实施吗?或者这是矫枉过正?

数据库

数据库是这样设置的:

+------------------------------------------------------------------------------+
|  users                                                                       |
+---------+--------------+--------------+---------------+----------------------+
| salt    | pub_key      | enc_priv_key | priv_key_hmac |                      |
+---------+--------------+--------------+---------------+----------------------+
|  entries                                                                     |
+---------+--------------+--------------+---------------+----------+-----------+
| user_id | parent_entry | enc_sym_key  | sym_key_sig   | enc_data | data_hmac |
+---------+--------------+--------------+---------------+----------+-----------+

基本用例

让我们想象一下系统的两个用户,Alice 和 Bob。

Bob注册该网站

  • Bob 输入密码。此密码被发送到服务器(但不存储)。
  • 服务器生成随机盐并将其存储在salt字段中。
  • 服务器生成 Bob 的密码和 salt 的 SHA-256 哈希。
  • 服务器生成一个 RSA 密钥对。公钥以纯文本形式存储在pub_key字段中。私钥通过 AES-256 使用 Bob 的密码和 salt 生成的哈希作为密钥进行加密,并存储在enc_priv_key字段中。
  • 服务器使用 Bob 的密码和 salt 作为密钥为 Bob 的私钥生成一个基于哈希的消息验证代码,并将其存储在priv_key_hmac字段中。

Bob在系统中存储一个条目

  • Bob 输入了一些数据和他的密码一起存储为条目。该数据被发送到服务器。
  • 服务器生成一个密钥,用作 AES-256 加密的密钥。
  • 服务器使用此密钥加密数据并将结果存储在enc_data字段中。
  • 服务器使用生成的密钥为数据生成基于散列的消息验证码,并将其存储在data_hmac字段中。
  • 用于加密数据的对称密钥使用 Bob 的公钥加密并存储在enc_sym_key字段中。
  • 服务器使用 Bob 的私钥生成对称密钥的签名。

Bob检索他存储的条目

  • Bob 输入他的密码和要检索的条目的 ID。
  • 服务器生成 Bob 的密码和 salt 的 SHA-256 哈希。
  • Bob 的加密私钥使用哈希通过 AES-256 加密进行解密。
  • 服务器通过检查 中的 HMAC 来验证 Bob 的加密私钥没有被篡改priv_key_hmac
  • enc_sym_key服务器使用 Bob 的私钥解密存储在该字段中的对称密钥。
  • sym_key_sign服务器通过使用 Bob 的公钥验证签名来验证加密的对称密钥没有被篡改。
  • 服务器使用对称密钥解密数据。
  • data_hmac服务器通过验证存储在字段中的 HMAC 来验证加密数据没有被篡改。
  • 服务器将解密后的数据返回给 Bob。

Bob与 Alice 共享一个条目

  • Bob 希望 Alice 能够访问他拥有的条目。他输入他的密码和要共享的条目的 ID。
  • 条目的数据使用“Bob 检索他存储的条目”中的方法解密。
  • 以与“Bob 在系统中存储条目”相同的方式为 Alice 创建一个新条目,但以下情况除外:
    1. 条目parent_entry设置为 Bob 的条目。
    2. 对称密钥的签名是使用 Bob 的私钥计算的(因为 Alice 的私钥对 Bob 不可用)。
    3. 当 Alice 访问这个新条目时,非空值的存在 parent_entry会导致系统使用 Bob 的公钥来验证签名(因为他的私钥被用来创建它)。

Bob更改了他共享条目中的数据

  • Bob 决定更改他与 Alice 共享的条目中的数据。Bob 指出要修改的条目 ID 和它应该包含的新数据。
  • 系统会覆盖在“Bob 在系统中存储条目”中创建的数据。
  • 系统找到与parent_entry刚刚修改的条目相等的每个条目,并为每个条目覆盖在“Bob 与 Alice 共享一个条目”中创建的数据。

分析

优点:

  • 如果没有拥有数据的用户的密码,就不可能从数据库中解密任何数据,因为解密数据所需的私钥是用用户的密码加密的,并且该密码(及其哈希值)不存储在数据库。
  • 如果用户想要更改他们的密码,只需要重新生成他们的加密私钥(用旧密码/哈希解密私钥,然后用新密码/哈希重新加密)。
  • 共享条目作为实际单独的记录存储在数据库中,因此无需在多个用户/用户组之间共享密钥。

缺点/问题(我能想到的):

  • 如果共享条目被修改,系统必须重新加密每个子条目;由于有大量用户共享数据,这可能在计算上很昂贵。
  • 共享条目依赖于父用户的公钥进行签名验证。如果用户被删除,或者他们的密钥发生变化,则签名无效。

从介绍中重复:我的问题是:这个实现安全吗?我错过了什么吗?如果是这样,上述规范甚至可以实施吗?或者这是矫枉过正?

谢谢你坚持这么久。我对你的意见很感兴趣!我是在正确的轨道上,还是一个彻头彻尾的白痴?你决定!:)

4

3 回答 3

1

You don't actually need to duplicate anything other than enc_sym_key when you share an entry with Alice - since the symmetric key is never re-used for more than one entry, you only need one copy of the encrypted data.

于 2011-03-28T05:21:11.423 回答
1

没有静脉储存?我猜你可以使用 AES-256-ECB,但它只允许用户存储 32 字节的密码,并且你需要确保生成的私钥只用于一次加密。(在这方面,您当前的设计似乎是安全的,但是如果您希望密码长度超过 32 字节,或者曾经考虑让此密钥执行双重任务,则需要为每次加密存储一个 IV。)

我看不到priv_key_hmacand的安全价值data_hmac;如果私钥或加密数据被篡改,则使用私钥或对称密钥解密将产生垃圾输出。BEL当 Bob 不知道如何输入字符时,他肯定会怀疑。:) (人类会看到输出吗?人类可能会意识到返回的密码不正确而无需被告知。计算机无法区分,因此如果自动化系统将使用生成的密码,那么当然,请保留田野。)

没有“我忘记密码”的机制。确保您的用户知道如果忘记密码,他们的数据将无法恢复。这些天来,用户被宠爱,并且可能期望也被您的服务宠爱。

我看不到用户指定Bob 想要解密哪个条目的机制。您应该为每个条目存储一个名称,或者像ssh(1)中一样known_hosts,存储一个名称的散列版本。直接存储名称将删除 SHA-256 操作,但报告用户拥有帐户的服务的明文名称的数据库泄露可能会造成破坏。(可能是在线护送服务、离岸银行或搏击俱乐部。)

于 2011-03-27T08:30:08.570 回答
0

为什么不使用证书在用户之间共享数据?使用 PKCS#12 证书保存用户的 PEM 和私钥,每个用户或每个站点的 PEM 可以签名和加密以进行数据验证和安全性。

一个场景来说明。

Bob 想在没有 Eve 阅读的情况下与 Alice 分享。

爱丽丝给鲍勃她的公钥。Bob 将 Alice 的公钥添加到他的受信任用户的钥匙串中。然后 Bob 使用 Alice 的公钥加密消息,同时使用他自己的 PEM 对数据进行签名。当然,这种情况要求 Alice 已经拥有 Bob 的公钥副本来执行签名验证,但您明白了。

另外,为什么要储存盐或静脉注射?在数据库受损的情况下,这两个与静态数据一起存储的数据都可以访问。

最佳实践...

  1. 为每个用户帐户使用一个密钥环来存储其他公钥/PEM 证书
  2. 仅使用公钥加密在帐户之间共享信息
  3. 使用不会在帐户之间共享的用户私钥加密数据
  4. 不要使用 AES、RSA 或任何其他可逆加密来存储密码
  5. 应使用用户特定的盐来进一步增强密码的散列算法,并且不应存储
  6. 使用站点范围的密码使用 AES 可以用于存储静态数据以进一步提高安全性(但您会遇到您在 CONS 部分中概述的问题)
于 2012-04-06T14:11:39.600 回答