在客户端,您可以使用 PBKDF2 或类似的密钥派生函数来生成密钥,然后在使用对称密钥之前对其进行加密/解密。这会被认为(可接受的)安全吗?
这实际上取决于几件事:
1. 什么是威胁模型?
你想阻止谁攻击你?民族国家?嫉妒的另一半?脚本小子?此人是否可以物理访问客户的设备?等等。
2.您使用什么作为 KDF 的输入(在您的示例中为 PBKDF2)?
希望 KDF 的输入不会保留在设备上(除了盐和轮,你可以把它们留在周围),而是一些足够的熵,用户被迫输入一次(例如,密码)然后在不再需要时从内存中擦除。
3. 您如何加密和存储密钥?
如果有可用的受信任的专用硬件(例如,TPM 或 HSM [假设您信任那些]),那么它们将为您提供一种存储对称密钥的方法(有些将它们存储在专用硬件上,有些使用存储的密钥对其进行加密)在硬件上,但将生成的密文存储在您的存储设备上)。如果没有这样的硬件可用,那么您通常会将密钥存储在密钥库中,该密钥库基本上是一个以加密方式存储密钥的文件(或文件集)。已经有几种实现方式,但如果您要推出自己的实现方式(我不推荐),那么您需要考虑如何保护加密密钥的机密性和完整性。需要考虑的一些事项是:
- 每个要加密的密钥会用不同的 KEK 包装吗?
- 您将如何得出每个 KEK?
- 您将使用哪些算法/模式?
- 你需要什么样的性能?
4. 当你不再需要它们时,你会如何处理内存中的键?
一旦不再需要每个密钥的每个副本,都应该从内存中擦除它们。关于如何做到这一点存在争议,从只是在内存中的字节上写入一堆零,到做更多涉及多次传递的花哨的事情,每一次将不同的字节写入内存中的密钥区域。你做什么应该取决于你的威胁模型。
服务器端有哪些可能性?将这样的密钥存储在数据库中的安全过程是什么?
服务器端有非常相似的选项。理想情况下,服务器将使用 HSM 并将密钥存储在其中(有关更多详细信息,请参见上面的 #3),并且您的服务器端应用程序将永远无法访问原始密钥字节(只有 HSM 可以)。在数据库中,您只需存储密钥的别名(您可以使用 HSM 提供数据库记录和别名之间绑定的完整性)。
例如,亚马逊如何存储用于 S3 查询字符串身份验证的对称密钥?
我不确定 Amazon 专门针对 S3 的查询字符串身份验证做了什么,但我知道他们提供了Cloud HSM 服务。