php - 如何使用 AES_ENCRYPT 和 PDO 准备语句改进大型加密数据库的 PHP 解决方法?
问题描述
在 MySQL 中使用准备好的语句,您必须只使用一次参数。像下面的例子这样的编码会引发“SQLSTATE[HY093]: Invalid parameter number”
$enigma = 'ThisIsTheSecretEncryptionKey';
$data = [
'name' => $name,
'first_name' => $first_name,
'gender' => $gender,
'birthdate' => $birthdate,
'email' => $email,
'profession' => $profession,
'enigma' => $enigma
];
$sql = "INSERT INTO members
(name , firstname , gender , birthdate, email, profession)
VALUES(
AES_ENCRYPT(:name, :enigma),
AES_ENCRYPT(:first_name, :enigma),
AES_ENCRYPT(:gender, :enigma),
AES_ENCRYPT(:birthdate, :enigma)
AES_ENCRYPT(:email, :enigma)
AES_ENCRYPT(:profession, :enigma)
)";
$pdo->prepare($sql)->execute($data);
为了克服这个问题,我找到了这个解决方案:
$enigma = 'ThisIsTheSecretEncryptionKey';
$data = [
'name' => $name,
'first_name' => $first_name,
'gender' => $gender,
'birthdate' => $birthdate,
'email' => $email,
'profession' => $profession,
'enigma' => $enigma,
'enigma2' => $enigma,
'enigma3' => $enigma,
'enigma4' => $enigma,
'enigma5' => $enigma,
'enigma6' => $enigma,
];
$sql = "INSERT INTO members
(name , firstname , gender , birthdate, email, profession)
VALUES(
AES_ENCRYPT(:name, :enigma),
AES_ENCRYPT(:first_name, :enigma2),
AES_ENCRYPT(:gender, :enigma3),
AES_ENCRYPT(:birthdate, :enigma4)
AES_ENCRYPT(:email, :enigma5)
AES_ENCRYPT(:profession, :enigma6)
)";
$pdo->prepare($sql)->execute($data);
它可以工作,但它不是一个真正顺利的解决方案,特别是当涉及到包含大量列的表时。有没有其他方法在 MySQL 的加密数据库中使用准备好的语句?
解决方案
至少有两种选择
首先,您可以启用PDO 的仿真模式(或者,不要在连接选项中禁用它)。在这种情况下,PDO 将开始对命名占位符做出明智的行为,并允许您重用它们,因此您只需定义一次。
$data = [
'name' => $name,
'first_name' => $first_name,
'gender' => $gender,
'birthdate' => $birthdate,
'email' => $email,
'profession' => $profession,
'enigma' => $enigma,
];
$sql = "INSERT INTO members
(name , firstname , gender , birthdate, email, profession)
VALUES(
AES_ENCRYPT(:name, :enigma),
AES_ENCRYPT(:first_name, :enigma),
AES_ENCRYPT(:gender, :enigma),
AES_ENCRYPT(:birthdate, :enigma)
AES_ENCRYPT(:email, :enigma)
AES_ENCRYPT(:profession, :enigma)
)";
另一种选择是使用 SQL 变量。您可以运行查询(如果对所有表使用相同的谜,您可以在连接后立即在每个脚本执行时运行一次此查询)
$pdo->prepare("SET @aes_enigma=:enigma")->execute([$enigma]);
然后在您的查询中使用此变量
$data = [
'name' => $name,
'first_name' => $first_name,
'gender' => $gender,
'birthdate' => $birthdate,
'email' => $email,
'profession' => $profession,
];
$sql = "INSERT INTO members
(name , firstname , gender , birthdate, email, profession)
VALUES(
AES_ENCRYPT(:name, @aes_enigma),
AES_ENCRYPT(:first_name, @aes_enigma),
AES_ENCRYPT(:gender, @aes_enigma),
AES_ENCRYPT(:birthdate, @aes_enigma)
AES_ENCRYPT(:email, @aes_enigma)
AES_ENCRYPT(:profession, @aes_enigma)
)";
但老实说,我会不惜一切代价避免加密数据库。可能是几个表中的一些选定字段。但是鉴于您不能对加密数据使用索引,因此只有一个最多几千行的玩具数据库才能真正可用。
推荐阅读
- groovy - 如何在 jekins 管道中使用 timer.runAfter()
- angular - Nebular:在 nbPopover 中的 nb-tabset 内使用时,nb-datepicker 不会检测到日期更改
- git - Git stash pop 错误 - 您对以下文件的本地更改将被合并覆盖
- python - 根据范围创建增量文件
- c++ - 为什么 C++ 允许重复 + 运算符,例如 x = 1 + + + + + + + + 2;
- r - R中的Choroplet映射
- javascript - 如何避免nodejs循环上的429
- php - 如何通过请求phpunit发送对象
- mysql - mysql 语法查询.difference between have 和 where 有什么区别
- javascript - 循环中的更新选项卡在 Chrome 扩展扩展中不起作用