我正在开展一个项目,我的宝贵信息必须存储在表'成员'中。表结构如下所示:
id | username | password | salt | last_name
———|——————————|——————————|——————|———————————
1 | VARCHAR | HASH | CHAR | BLOB
2 | VARCHAR | HASH | CHAR | BLOB
3 | VARCHAR | HASH | CHAR | BLOB
4 | VARCHAR | HASH | CHAR | BLOB
5 | VARCHAR | HASH | CHAR | BLOB
在此示例中,last_name
使用密钥加密。该密钥存储在表'keys'中:
id | key
———|——————
1 | BLOB
2 | BLOB
3 | BLOB
4 | BLOB
5 | BLOB
这些密钥也使用另一个密钥加密,该密钥源自未散列的密码,id和用户名。
我认为这是保存,因为如果数据库被盗,盗贼无法导出表'密钥'中的密钥,最终无法导出解密last_name
。
我想确定这是否真的是保存,或者是否有另一种存储密钥的方法。
答案 0 :(得分:1)
这称为密钥包装,是的,它是安全的,但是当你加密密钥时,你应该使用专门为它设计的密码。 This question对于原因有一个不错的解释。
不确定您使用的语言是什么,但在Java中,您可以这样做:
Key rootKey = new SecretKeySpec(keyBytes, "AES");
KeyGenerator generator = KeyGenerator.getInstance("AES");
generator.init(128);
Key keyToWrap = generator.generateKey();
Cipher cipher = Cipher.getInstance("AESWRAP");
cipher.init(Cipher.WRAP_MODE, rootKey);
byte[] wrappedKey = cipher.wrap(keyToWrap);
Cipher uncipher = Cipher.getInstance("AESWRAP");
uncipher.init(Cipher.UNWRAP_MODE, rootKey);
Key unwrappedKey = uncipher.unwrap(wrappedKey, "AES", Cipher.SECRET_KEY);
还要确保使用良好的密钥派生函数(如SCrypt)来派生每个用户的根密钥。 Bouncy Castle具有Java和C#的SCrypt实现,以及它自己的密钥包装实现。或者您可以找到PHP SCrypt实现here。
请记住但是,根据您的方案,如果用户忘记了密码,您将无法恢复其加密数据,因为其根密钥是从密码派生的。