在MySQL中加密/解密大文本数据的推荐方法是什么?

时间:2011-09-09 12:34:51

标签: php mysql security encryption aes

我有一个在Intranet上运行的客户端/服务器应用程序,我需要在数据库的一个表的一个字段中加密数据。该字段目前是TEXT数据类型,我所学到的并不适合MySQL中的加密。存储在该字段中的文本类似于包含来自主管的叙述性评论的员工绩效评估。由于系统运行的网络的个人信息限制,此数据不能以纯文本格式存储。数据还需要通过应用程序的客户端具有不同“角色”(身份验证级别)的不同用户进行编辑。

所以......我一直在研究如何加密这些数据,这是我目前所理解的:

  • MySQL文档解释了AES函数,我应该更改可能是BLOB的字段数据类型以容纳加密信息。
  • 密钥必须修复(即没有使用用户密码等,因为我已阅读过SO),因为不同的用户需要能够编辑/审核评论。
  • 我认为最好的选择是存储密钥并将其作为变量传递给php代码,类似于我对应用程序的MySQL登录信息所做的。

在这种情况下使用AES功能是一种合适的方式来继续这个,还是我不知道的问题?由于文本的潜在长度,我确实对问题(性能?)感到疑惑。我发现的大多数示例都涉及加密较小的数据:例如姓名,地址,信用卡号码等。

任何建议都将不胜感激。提前谢谢!

2 个答案:

答案 0 :(得分:6)

使用AES,在CBC或CTR模式下都可以。避免使用ECB模式,因为它不安全。使用PKCS7填充。

如果要将加密文件存储为文本而不是BLOB,则在保存到数据库之前将二进制密文转换为Base64。 Base64仅使用文本字符。显然,您需要在解密之前将Base64转换回二进制文件。

您的主要问题是密钥处理,因为每个有权访问数据库的人都需要密钥,而您无法将密钥存储在数据库本身中。您可能希望就此采取一些专家建议,因为它很重要。

答案 1 :(得分:3)

数据库的安全性

首先,您需要问问自己:“为什么要加密数据库中的数据?” 原因是数据库可能落入坏人手中 因此,您无法将密钥存储在数据库本身中 您必须假设攻击者知道数据库中的所有数据。

因此,唯一的答案是将密钥放在DB之外 我建议使用与文章相同的行中的数据来加密密钥,以便攻击者不能对所有文章使用彩虹表。

pseudocode for select statement:

SELECT AES_DECRYPT(article, CONCAT(salt, '$secret_key')) FROM articles
WHERE id = '123' 

PHP安全性
请注意,在PHP源代码中列出AES加密密钥也将失败 它必须只存在于计算机上并且需要安全的内存中 一个选项是从远程计算机(加密传输)读取它是安全的(带有警卫的数据中心)或在程序启动时有一个高级官方密钥。

如何避免MySQL ECB漏洞
如果你需要真正安全,你将不得不在PHP中进行加密。

请参阅此文章,了解为何MySQL (使用ECB模式)存在问题:http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29

伪代码

<?pseudophp
$secretmessage = $_GET['secret_message_from_user'];
$randomprefix = hash('sha512',$timestampinmilliseconds);
$secretmessage = $randomprefix."@@@@".$secretmessage; 
//$password = "really long password entered by a trusted superuser";
$key256 = hash('sha512',$password); //stuff the password into 256 bits.
//You'll have to check that the output is really 256 bits, an tweak it if not.
$iv =  '1234567890123456'; //this is public, because the iv is already in the text.

printf("iv: %s\n",bin2hex($iv));
printf("key256: %s\n",bin2hex($key256)); //debug stuff
printf("message before\n %s\n",$secretmessage);

//We use AES aka RIJNDAEL.
$cipher = mcrypt_module_open(MCRYPT_RIJNDAEL_256, '', MCRYPT_MODE_CBC, '');
if (mcrypt_generic_init($cipher, $key256, $iv) != -1)
{
  // PHP pads with NULL bytes if $cleartext is not a multiple of the block size..
  $cipherText = mcrypt_generic($cipher,$cleartext );
  mcrypt_generic_deinit($cipher);
  // Display the result in hex.
  printf("256-bit encrypted result:\n%s\n\n",bin2hex($cipherText));
}