【问题标题】:MySQL encrypted columnsMySQL 加密列
【发布时间】:2010-09-19 06:21:09
【问题描述】:
假设表中的每一行都有与某个特定用户相关的数据。用户拥有访问系统的密码。
如何使用 InnoDB 加密一列数据,以便除了数据的用户之外没有其他人可以读取数据?我正在考虑使用 MySQL 加密函数之一(比如 AES)和基于从用户密码计算的哈希值的密钥。
有没有人对我如何做到这一点有任何指示?我在正确的轨道上吗?
以下答案之一
修改用户密码的问题涉及使用新密码重新加密用户密钥,这比重新加密可能任意大的大量用户数据要简单得多。用户密钥在系统中用户数据的整个生命周期内保持不变。
这有什么帮助?假设密码是pass1。并且有一堆使用由此生成的密钥加密的记录。如果用户现在将密码重置为 pass2,我将无法解密使用 pass1 加密的数据。如果用户完全忘记密码,他的所有加密数据都将丢失。
【问题讨论】:
标签:
mysql
security
encryption
【解决方案1】:
我不知道用用户的密码哈希加密数据是否有意义,尤其是如果你将哈希本身保存在数据库中。在这种情况下,任何可以访问加密数据的人也可以访问密码哈希并解密数据。
另一种方法是使用特定于应用程序的密钥与一些特定于用户的数据一起加密数据。但是,接下来您将面临另一个问题:如何安全地存储应用程序密钥。对于这个问题,我不知道一个简单的答案,但是如果您担心您的数据库数据可能会受到损害,而不是源代码本身,例如,将其保存在您的源代码中可能就足够了。如果您的数据库存储在异地(想想 Amazon S3)。
如果您在数据库中仅保留密码的哈希值,使用用户密码对应用程序密钥进行加盐会有所帮助,但可能会引入另一个安全漏洞:您必须在应用程序会话中以明文形式保存用户密码。
至于技术方案,很简单,sample code is available。您可以对其进行如下修改,以使用密码哈希加盐的应用程序密码来加密数据:
INSERT INTO secure_table VALUES (
1,
AES_ENCRYPT(
'plain text data',
CONCAT(@application_password, @user_password))
);
在任何情况下,您都必须将应用程序密码存储在某个地方,因此我认为没有一种简单的方法可以提供完美的安全性。
我能想到的另一种方法是要求用户输入一个简短的 PIN,您可以将其用作加密密钥。 PIN 不会存储在数据库中,但您需要在每次访问用户数据时向用户询问。
当然你要考虑的是加密的可行性。如果不解密,您将无法索引或搜索它。有限的数据集(例如信用卡号)可能需要它,但我不会走得太远。
【解决方案2】:
澄清问题中提到的答案之一:“用户/应用密钥”是随机生成的私钥,用于加密数据。私钥永远不会改变(除非它被泄露)。您使用密码加密和存储私钥。由于私钥比数据小得多,因此更改密码要便宜得多:您只需使用旧密码解密私钥并使用新密码重新加密即可。
【解决方案3】:
对于非用户特定(全局)的数据,您可以使用对称和非对称密码的组合。您可以有一个所有用户都必须输入的extra password 字段,这样即使一个用户更改了自己的密码,全局数据仍然可供使用不同密码的其他用户使用。
extra password 可以与源代码中的另一个salt-like string 按位异或。一起,它可以形成对称密钥来解密存储在数据库中的private key(永远不会改变)。使用extra password解密private key后,私钥可以解密read数据库中的所有数据。私钥可以存储为会话变量。
public key,顾名思义,可以作为纯文本字符串驻留在数据库中。当你需要write到db时,使用公钥加密数据。
您可以定期为用户提供一个新的extra password 并重新加密静态private key,然后与salt-like string 进行异或。
如果数据是特定于用户的数据并且不用于其他用户,您可以使用不带额外密码字段的用户密码来加密私钥。管理员可以拥有另一个特定用户的私钥副本,可以使用他的密码对其进行解密。
【解决方案4】:
我认为这不是最好的方法,除非你强制用户永远不能更改他们的密码,或者你有办法在用户每次更改他/她的密码时重新加密所有内容。
【解决方案5】:
您可以存储另一个密钥来加密/解密在创建新用户时可能生成的用户特定数据。我们称这个新的密钥用户密钥。这个用户密钥也应该在数据库中加密,最直接的方法是通过用户的密码或包含密码的任何其他数据(如密码和创建/修改时间等)对其进行加密。
我会在用户会话中保留解密的用户密钥,以便在会话中的任何所需时间访问用户的数据。
修改用户密码的问题涉及使用新密码重新加密用户密钥,这比重新加密可能任意大的大量用户数据要简单得多。用户密钥在系统中用户数据的整个生命周期内保持不变。
当然,只有在登录时通过将实际用户密码发送到服务器来执行身份验证时才能使用此方法,因为数据库只希望包含密码的哈希值。
【解决方案6】:
假设密码是pass1。并且有一堆使用由此生成的密钥加密的记录。如果用户现在将密码重置为 pass2,我无法解密使用 pass1 加密的数据
密钥需要以可逆方式加密,以便可以解密
使用 pass1 并使用 pass2 重新加密。
总结一下:
在数据库中存储的是:单向加密密码(用于密码校验),
其他数据的加密密钥,使用明文密码进行可逆加密(或者无论如何,密码以与数据库中存储方式不同的方式加密),以及其他数据,使用明文加密密钥进行可逆加密。
当您需要其他数据时,您必须拥有明确的(或与数据库中存储的密码不同的加密)密码,读取加密密钥,使用密码对其进行解密,然后使用该密码来解密其他数据。
更改密码时,使用旧密码解密加密密钥,使用新密码加密并存储。
【解决方案7】:
如果您需要在没有用户交互的情况下访问数据(例如用于数据库迁移),您将没有解密的密钥。