暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

MySQL加密:InnoDB中的主密钥加密

原创 Pinal Dave 2019-12-24
1995

信封加密的思想是使用一个密钥对多个其他密钥进行加密。在InnoDB中,此“一个密钥”是主加密密钥,“其他多个密钥”是表空间密钥。这些表空间密钥是实际用于加密表空间的密钥。它可以以图形方式显示为:

image.png

主密钥位于密钥环中,而加密的表空间密钥位于表空间标题(写在表空间的第0页)中。在上图中:

表A用密钥1加密。密钥1用主密钥加密,并存储(加密)在表A的头中。

表B用密钥2加密。密钥2用主密钥加密,并存储(加密)在表B的头中。

等等。当服务器要解密表A时,它将从密钥环中获取主密钥,从表A的标头中读取加密的密钥1,然后解密密钥1。解密的密钥1缓存在服务器内存中,并用于解密表A。

InnoDB

在InnoDB中,实际的加密/解密在服务器的I / O层中完成。因此,在将页面刷新到磁盘之前,它就被加密了,而且从磁盘读取了一个加密页面之后,它也被解密了。

InnoDB中的加密仅在表空间级别上起作用。通常,在创建独立表时,会创建每个表文件表空间(默认情况下为ON)。因此,您实际创建的是一个只能包含一个表的表空间。您还可以创建一个属于常规表空间的表。无论哪种方式,您的表始终位于某个表空间内。由于加密在表空间级别上进行,因此表空间可以完全加密或完全不加密。因此,不能在常规表空间中对某些表进行加密,而对某些表则不能。

如果由于某种原因禁用了每表文件,那么实际上所有独立表都是在系统表空间内创建的。在Percona Server for MySQL中,可以通过在引导过程中指定(变量innodb_sys_tablespace_encrypt)或使用加密线程(仍是实验性功能)来加密系统表空间。在MySQL中,您不能;)。

在继续之前,我们需要了解如何创建主密钥ID。它由UUID,KEY_ID和前缀INNODBKey组成。看起来像这样:INNODBKey-UUID-KEY_ID。

UUID是在其中加密表空间的服务器的uuid。KEY_ID只是一个不断增加的值。创建第一个主密钥时,此KEY_ID等于1。然后旋转主密钥时,将创建一个新的主密钥,其KEY_ID = 2,依此类推。

现在我们知道主密钥ID是什么样的,我们可以看一下加密头。第一次加密表空间时,会将加密头添加到表空间头中。看起来像这样:

image.png

KEY ID是我们已经讨论过的主密钥ID中的KEY_ID。UUID是服务器uuid,以后用于主密钥ID。表空间键由256个随机(由服务器生成)位组成。表空间IV还包含256个随机生成的键(尽管它应该是128位)。IV用于初始化AES加密和解密(仅使用这256位中的128位)。最后,我们有表空间密钥和IV的CRC32校验和。

我一直在说,标题中有一个加密的表空间密钥。实际上,我们将表空间密钥和IV捆绑在一起存储,并使用主密钥对它们进行加密。记住,在加密表空间密钥和IV之前,我们首先要计算两者的CRC32。

为什么我们需要CRC32?

为了确保我们使用正确的主密钥来解密表空间密钥和IV。解密表空间密钥和IV之后,我们计算校验和,并将其与存储在标头中的CRC32进行比较。如果它们匹配,我们知道我们使用了正确的主密钥,并且拥有有效的表空间密钥和表空间iv来解密表。如果它们不匹配,我们将表空间标记为丢失(无论如何我们将无法对其进行解密)。

您可能会问–我们什么时候检查我们是否有正确的主密钥来解密所有表?答案是:在服务器启动时。在启动时,每个加密的表/表空间服务器从标头读取UUID,KEY_ID以构造主密钥ID。接下来,它从Keyring获取所需的主密钥,解密表空间密钥和iv,并检查校验和。同样,如果校验和匹配,我们都很好,否则,表空间被标记为丢失。

基于服务器的密钥环仅在服务器启动时获取密钥ID列表(准确地说是密钥ID和用户ID,因为这对唯一标识密钥环中的密钥)。现在,要说的是服务器获取启动时所需的所有密钥,以验证它可以解密表空间密钥。那么,为什么基于服务器的密钥环在初始化时仅获取key_id和user_id而不是获取所有密钥?因为并非所有键都需要;这主要是由于主键旋转。主密钥轮换将在密钥环中生成一个新的主密钥,但绝不会删除该主密钥的旧版本。因此,您最终可能会在密钥服务器(Vault服务器,如果您使用的是keyring_vault)中拥有许多服务器不需要的密钥,因此在服务器启动时不会获取这些密钥。

现在是时候讨论主密钥加密的利弊了。最大的优点是您只需要一个加密密钥(主密钥)即可与加密数据分开存储。这使得服务器启动速度更快,密钥环更小,从而更易于管理。同样,可以用一个命令旋转主键。

但是,主密钥加密有一个很大的缺点。一旦使用tablespace_key对表空间进行了加密,它将始终使用相同的密钥进行加密。万能钥匙旋转在这里无济于事。为什么这是不利的呢?我们知道MySQL的错误可能会使它突然崩溃,从而生成一个核心文件。由于核心文件包含服务器的内存转储,因此该核心转储可能包含解密的表空间密钥。更糟糕的是,已解密的表空间密钥存储在可以交换到磁盘的内存中。可以说这不是缺点,因为您需要具有root用户访问权限才能访问那些核心文件/交换分区。的确如此–但是您只需要一段时间才能进行root用户访问。一旦某人可以访问已解密的表空间密钥,即使该人不再可能进行根访问,他/她也可以继续使用它来解密数据。同样,磁盘可能被盗,交换分区/核心文件可以通过不同的方式读取,TDE的目的是即使磁盘被盗也无法读取。Percona Server for MySQL提供了一项功能,使使用新生成的密钥对表空间进行实际的重新加密成为可能。此功能称为加密线程,在撰写本文时仍处于试验阶段。

来源:https://www.percona.com/blog/2019/12/19/mysql-encryption-master-key-encryption-in-innodb/

「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

文章被以下合辑收录

评论