3

我有一种情况,我必须存储密码,因为我正在构建一个系统以连接到另一个系统。这个其他系统只允许一个用户帐户,并且连接到它的唯一方法是通过密码。哈希在这里不合适。我必须以可以检索的方式存储密码。

现在,知道这不是一个完美的系统,我正试图限制如果有人以某种方式访问​​数据库的损害。由于这个数据库需要被不同的平台使用,我决定使用 MySQL 自己的内置加密功能。这样,我就不用担心为各种语言和系统找到兼容的加密/解密算法实现了。我可以在查询中使用 MySQL 的函数。

存储密码时,我将使用AES_ENCRYPT("password", "encryption key"). 然后我意识到我可能应该使用一些盐,这样如果他们能够获得一个密码,就很难获得其他密码。可是等等!重点是什么?如果他们能够获得一个密码,他们必须拥有加密密钥,是吗?

此外,这是一个分组密码。在某些情况下,盐几乎是无用的。

/* Returns 8CBAB2A9260975FF965E5A7B02E213628CBAB2A9260975FF965E5A7B02E21362FBB5D173CBAFA44DC406B69D05A2072C */
SELECT HEX(AES_ENCRYPT("passwordpasswordpasswordpassword", "encryption key"));

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

我的问题

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

  • 鉴于我必须以允许我检索原始值的方式存储密码,我应该考虑其他方法吗?(我知道我需要注意加密密钥的存储位置和方式,并且我还需要保护我的 MySQL 日志。)

4

1 回答 1

6

通常对于标准 AES,您会提供一个随机数(IV),以避免您描述的问题。

一种大幅提高加密数据质量的方法是为每个帐户使用不同的主密码,而不是改变 IV。基本上,这是您与密码混合的一些数据。你可以通过多种方式做到这一点,最简单的是做一个 concat。

例如

  1. 创建一个随机序列。
  2. 存储随机数 || HEX(AES_ENCRYPT(password_to_store, master_password || nonce)
  3. 通过提取随机数进行检索,然后使用 master_password || 解密数据 随机数。

这是一个示例,具有唯一的 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 的版本安全得多,但仍然存在很多弱点和攻击向量。例如,查询记录或嗅探 mysql 数据包将同时显示密码和主密码!

于 2013-03-31T22:29:20.363 回答