块密码、盐、AES、MySQL以及凭据存储最佳实践

3
我有一个情况,必须存储密码,因为我正在构建一个系统来连接另一个系统。这个其他系统只允许单个用户帐户,并且唯一连接它的方式是通过密码。散列在此处不合适。我必须以一种可以检索它的方式存储密码。
现在,知道这不是完美的系统后,我正在尝试限制如果某人以某种方式访问数据库会造成的损害。由于这个数据库需要被不同的平台使用,我决定使用MySQL内置的加密函数。这样,我就不需要担心为各种语言和系统寻找兼容的加密/解密算法实现。我可以在查询中使用MySQL的函数。
存储密码时,我将使用。然后我意识到我应该使用一些盐,这样如果他们能够得到一个密码,要获得其他密码会更难。但是等等!有什么意义吗?如果他们能够得到一个密码,他们必须有加密密钥,对吗?
此外,这是一个块密码。在某些情况下,盐可能几乎无用。
/* Returns 8CBAB2A9260975FF965E5A7B02E213628CBAB2A9260975FF965E5A7B02E21362FBB5D173CBAFA44DC406B69D05A2072C */
SELECT HEX(AES_ENCRYPT("passwordpasswordpasswordpassword", "encryption key"));

/* Returns 8CBAB2A9260975FF965E5A7B02E213628CBAB2A9260975FF965E5A7B02E21362C49AF8D5B194770E64FEF88767206391 */
SELECT HEX(AES_ENCRYPT("passwordpasswordpasswordpassworda", "encryption key"));

我的问题

  • 我是否正确地认为,在像我这样的情况下使用对称加密时,没有理由使用盐?

  • 考虑到我必须以一种允许我检索原始值的方式存储密码,我是否应该考虑其他任何方法?(我知道我需要小心加密密钥的存储位置和方式,并且我需要保护我的 MySQL 日志。)


你应该使用CBC;盐是IV。 - SLaks
3
考虑使用非对称加密,使得加密密码的机器(网络服务器?)无法解密它们(以防被攻破)。 - SLaks
@SLaks,好主意SLaks!我想MySQL没有提供任何不对称算法,但是我认为在这种情况下值得付出努力去实现。我会看看RSA。 - Brad
@SLaks,很酷的是看到你为我刚刚查看的项目做出了贡献:https://github.com/Obvious/ursa - Brad
不客气!听起来我们正在做完全相同的事情。您应该为每一行生成一个随机对称密钥,并使用RSA密钥进行加密。另请参阅http://www.daemonology.net/blog/2009-06-11-cryptographic-right-answers.html。 - SLaks
1个回答

6
通常对于标准的AES加密,您需要提供一个随机数(即IV),以避免您所描述的问题。为了大幅提高加密数据的质量,一种方法是为每个账户使用不同的主密码,而不是改变IV。基本上,这是一些与密码混合的数据。您可以通过多种方式完成此操作,最简单的方法是执行连接操作。 例如: 1. 创建随机序列。 2. 存储nonce || HEX(AES_ENCRYPT(password_to_store, master_password || nonce)) 3. 通过提取nonce来检索数据,然后使用master_password || nonce解密数据。 以下是一个示例,其中有唯一的nonce“iej383u8fjeiw”(每次加密时都需要生成新的)。
SELECT CONCAT('iej383u8fjeiw', ':', HEX(AES_ENCRYPT("password", CONCAT("master_password", "iej383u8fjeiw")))) 
-> "iej383u8fjeiw:61224653D4DA33D57A42FE5E5E10DEA9"

SELECT AES_DECRYPT(UNHEX(SUBSTRING_INDEX('iej383u8fjeiw:61224653D4DA33D57A42FE5E5E10DEA9', ':', -1)), CONCAT('master_password', SUBSTRING_INDEX('iej383u8fjeiw:61224653D4DA33D57A42FE5E5E10DEA9', ':', 1))) 
-> "password"

或者使用变量:

SELECT CONCAT(nonce, ':', HEX(AES_ENCRYPT(password_to_encrypt, CONCAT(master_password, nonce)))) 
-> encrypted password

SELECT AES_DECRYPT(UNHEX(SUBSTRING_INDEX(encrypted_password, ':', -1)), CONCAT(master_password, SUBSTRING_INDEX(encrypted_password, ':', 1)))
-> password_to_encrypt

虽然带有nonce的版本比没有nonce的版本安全性显著提高,但仍存在许多弱点和攻击向量。例如,记录查询或嗅探MySQL数据包将泄露密码和主密码!


请问,我应该使用什么数据类型来存储这个表中的数据?数据长度应该是多少? - Nikunj Kabariya
在这个例子中,密码存储在数据库中,因此长度取决于密码的长度。如果使用AES-128,则每个块的长度为16字节,因此最小长度为16字节,上限取决于密码的最大长度。这与使用具有固定长度的哈希不同。如果结果以十六进制形式存储,则使用varchar列就足够了。 - Nuoji

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接