Creating a secure, web-based password management system with the ability to share data between users
我提前为收到的wall-o-text道歉。这是(至少对我来说)一个相当复杂的问题,我已经考虑了很多。如果您愿意的话,您可以阅读我的问题,也可以在这个Github Gist中看到Ruby中的测试实现(非常仓促地构建,没有数据库支持,可能非常丑陋)。
介绍假设需要一个来创建一个基于Web的密码管理系统(通过SSL!:)有以下要求:
我不是密码学专家。我想了一会儿,就上来了以下内容。我的问题是:这个实现是安全的吗?我是错过什么?如果是,上述规范是否可以实现?还是这个过度杀戮?
数据库数据库的设置如下:
1 2 3 4 5 6 7 8 9 | +------------------------------------------------------------------------------+ | 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并将其存储在
salt 字段中。 - 服务器生成Bob密码和salt的sha-256哈希。
- 服务器生成一个RSA密钥对。公钥以普通格式存储
pub_key 字段中的文本。私钥通过AES-256加密使用从Bob的密码和salt生成的哈希作为密钥和存储在enc_priv_key 字段中。 - 服务器为Bob生成基于哈希的消息身份验证代码使用Bob的密码和salt作为密钥并将其存储在
priv_key_hmac 字段。
Bob在系统中存储一个条目:
- Bob输入一些数据,与密码一起作为条目存储。此数据将发送到服务器。
- 服务器生成一个密钥,用作AES-256加密的密钥。
- 服务器使用此密钥加密数据并将结果存储在
enc_data 字段。 - 服务器为使用生成的密钥的数据,并将其存储在
data_hmac 字段中。 - 用于加密数据的对称密钥是用Bob的public加密的并存储在
enc_sym_key 字段中。 - 服务器使用Bob的私钥为对称密钥。
Bob检索存储的条目:
- Bob输入密码和要检索的条目的ID。
- 服务器生成Bob密码和salt的sha-256哈希。
- Bob加密的私钥通过使用搞砸。
- 服务器验证Bob的加密私钥没有通过检查
priv_key_hmac 中的HMAC来篡改。 - 服务器解密存储在
enc_sym_key 字段中的对称密钥。使用鲍勃的私人钥匙。 - 服务器验证加密的对称密钥是否未被篡改。通过使用Bob的公钥验证
sym_key_sign 中的签名。 - 服务器使用对称密钥解密数据。
- 服务器验证加密数据是否未被篡改通过验证存储在
data_hmac 字段中的hmac。 - 服务器将解密的数据返回给Bob。
Bob与Alice共享一个条目:
- 鲍勃想让艾丽斯进入他拥有的一个入口。他进入他的密码和要共享的条目的ID。
- 条目的数据使用"bob retrieves"中的方法解密。他存储的条目。"
- 为Alice创建的新条目与"Bob Stores"中的样式相同系统中的一个条目,"除以下例外:
- 条目的
parent_entry 设置为Bob的条目。 - 对称密钥的签名是使用Bob的private计算的密钥(因为Bob无法使用Alice的私钥)。
- 当Alice访问这个新条目时,存在一个非空的
parent_entry 使系统使用bob的公钥来验证签名(因为他的私钥被用来创建它)。
Bob更改共享条目中的数据:
- Bob决定更改他与Alice共享的条目中的数据。鲍勃表示th
当您与Alice共享一个条目时,实际上不需要复制除
enc_sym_key 以外的任何内容-因为对称密钥从不用于多个条目,所以您只需要一个加密数据的副本。无静脉输液储存?我想您可以使用aes-256-ecb,但这只允许用户存储32字节的密码,您需要确保生成的私钥仅用于一次加密。(在这方面,您当前的设计似乎是安全的,但是如果您希望允许密码超过32个字节,或者曾经考虑让这个密钥执行双重任务,则需要为每个加密存储一个IV。)
我看不到
priv_key_hmac 和data_hmac 的安全值;如果私钥或加密数据被篡改,那么用私钥或对称密钥解密会导致垃圾输出。如果鲍勃不知道如何输入BEL 字符,他肯定会怀疑的。:)(人类会看到输出吗?一个人很可能会意识到返回的密码是不正确的,不需要告诉。计算机无法区分,因此,如果自动化系统使用生成的密码,那么当然要保留这些字段。)没有"我忘记密码"的机制。确保您的用户知道,如果忘记了密码,就无法恢复他们的数据。这些天,用户们都被宠坏了,他们可能也会被你的服务宠坏。
我看不到用户指定Bob要解密哪个条目的机制。您应该为每个条目存储一个名称,或者像
ssh(1) 在known_hosts 中那样,存储一个名称的哈希版本。直接存储一个名称会删除一个sha-256操作,但是如果数据库泄露了一个用户拥有帐户的服务的明文名称,那么这可能会造成非常大的破坏。(可能是网上护送服务,或离岸银行,或搏击俱乐部。)为什么不使用证书在用户之间共享数据?使用pkcs 12证书持有用户的PEM和私钥,每个用户或每个站点的PEM可以签名和加密以进行数据验证和安全性。
要说明的场景。
鲍勃想和艾丽丝分享而不需要夏娃阅读。
爱丽丝把她的公钥给了鲍勃。Bob将Alice的公钥添加到他信任用户的密钥链中。然后,Bob使用Alice的公钥加密消息,同时使用自己的PEM对数据进行签名。当然,这个场景要求Alice已经有了一个Bob的公钥副本来执行签名验证,但是您得到了这个想法。
另外,为什么要储存盐或静脉注射?这两个存储在一起的静态数据将在数据库受损的情况下被访问。
最佳实践…
- 为每个用户帐户使用一个密钥环来存储其他公钥/PEM证书
- 仅使用公钥加密在帐户之间共享信息
- 使用不在帐户之间共享的用户私钥加密数据
- 不要将AES、RSA或任何其他可逆加密用于密码存储
- 应使用用户特定的盐进一步增强密码的哈希算法,不应存储这些盐。
- 使用站点范围的密码使用AES可以用于存储静态数据以进一步提高安全性(但您会遇到在cons部分中概述的问题)。