首页 > 解决方案 > 从 MySQL 普通数据库值迁移到完全 AES 加密值 (PHP APi)

问题描述

短的:

由于 GDPR 法规,从纯文本数据库值迁移到完全/完全加密值的最佳方法?

解释器:

我刚刚收到一个“提示”,由于 GDPR(欧盟通用数据保护条例)法律要求的新“设计隐私”概念,所有“敏感”信息都需要加密。这包括姓名、地址、社交媒体资料、..

我们目前正在为 2000 多个用户运行一个完整的生产数据库,只能通过我们的 PHP REST API 访问,该 API 用作所有 Web 和移动应用程序的入口点(尚无第三方开发人员)。该数据库包含当前以纯文本形式存储的电子邮件地址、地址、社交媒体句柄、姓名、IP 地址......(除了基于安全的敏感信息,如密码、令牌......或用于身份验证的任何其他值/鉴别)。

我不是这个(开发方面)的忠实粉丝,因为市长对性能、搜索算法、整个 PHP API 等的影响(感觉就像整个优化和“完美设置数据库”的结束),但因为它是必需的因为它是额外的保护层,所以我全力以赴。

现在,我主要关心的是......一切都在积极运行,我们不能只是说“好的,关闭服务器,加密一切,部署新的 API 版本并重新打开它。”。此外,我认为这种迁移不能“一步一步”完成,所有事情都必须一次完成。如果 API 未准备好在所有查询中处理解密,则无法加密数据库值,反之亦然,如果 API 期望所有内容都被加密,则数据库不能是纯文本。

(我很高兴我将整个 API 类型的交易作为数据库的唯一入口/读取点,没有自定义脚本/连接,所以这是一种解脱)

我们正在运行一个功能强大的 VPS 服务器,因此由于冗余检查和诸如此类的东西会导致一些性能损失,而且我们也在运行 staging/dev 环境,所以测试没有问题。

我会让 MySQL 为每条记录使用唯一键处理 AES,该键基于 ID(主键)和创建时间戳的组合,例如(这两个值永远不会改变)(这可能不是那么聪明万一“出于某种原因”这个值确实发生了变化,数据已经消失了..所以不确定),这样我的 PHP 应用程序在运行查询时不需要以纯文本形式传递密钥,但是又一次, “创建解密密钥”在查询日志等中仍然可见,因此“最安全”的方法是让 PHP 应用程序加密和解密所有传入/传出数据,但这会导致无法例如运行“搜索查询”(除非我在这些特定查询中发送密钥..)。

我的问题:

怎么会这样..?我应该让 PHP 处理加密/解密还是更好的 MySQL?当记录被请求时,是否有一种可用的方法可以迁移到加密值?..?

我的想法是不触及任何数据库值(除了更新每个非整数列以处理当前指定的字符数量的 2-3 倍),这可以在不影响生产的情况下完成。然后逐步更新所有 API 查询,以检查所选值是否已加密。当一个部分运行正常时,更新该部分的表以加密所有值。作为一个(简单的)例子

MySQL方式;每个 SELECT 查询:

SELECT IF_AES_ENCRYPTED(first_name, AES_DECRYPT(first_name), first_name) AS first_name FROM contacts WHERE id = 1;

(或)PHP 方式:检索数据:

while ($row = $result->fetch_assoc()) {
  $contact->setFirstName((IS_AES_ENCRYPTED($row['first_name']) ? AES_DECRYPT($row['first_name']) : $row['first_name']);
}

在部署结束时:

UPDATE contacts SET first_name = AES_ENCRYPT(first_name);

肯定有办法做到这一点,但由于我是目前唯一的开发人员,我只是不确定什么是最实用/最有效的方法,或者我是否过度或考虑不足或不。只是在寻找其他执行过这样的迁移/更新的开发人员。

谢谢,伯特。

标签: phpmysqlencryptionmigration

解决方案


我会通过添加一个新列first_name_enc来存储字符串的加密版本来做到这一点。

然后,您可以在过渡到完全加密时临时存储加密和未加密的值。

ALTER TABLE contacts ADD COLUMN first_name_enc VARBINARY(...);

当你读取值时,解密它,但如果值为 NULL,那么它必须是尚未转换的行,所以回退到原始的未加密列。

SELECT COALESCE(AES_DECRYPT(first_name_enc, <key-string>), first_name) ...

在整个应用程序中放置此代码后,您可以开始批量转换行:

UPDATE contacts SET
  first_name_enc = AES_ENCRYPT(first_name, <key-string>), 
  first_name = NULL
WHERE id BETWEEN 1 AND 1000;

在您完成将所有内容转换为加密并且您的应用程序不再插入未加密的列之后,您可以将条件查询转换为简单地读取加密的列并对其进行解密。

SELECT AES_DECRYPT(first_name_enc, <key-string>) ...

然后最后删除未加密的列,因为它们现在只包含 NULL。

ALTER TABLE contacts DROP COLUMN first_name;

我建议您在投入时间进行这项工作之前,先确认您真正需要做的有关加密的事情。我读过声称 GDPR 实际上并未强制加密的文章。https://www.i-scoop.eu/gdpr-encryption/

但对互联网文章持保留态度。请咨询合格的专家。即使支付专业专家的咨询费,也可能为您节省数以万计的软件开发成本!


推荐阅读