通常我们不会在mysql层面上使用加密插件, 虽然加密之后会比较安全, 但加密太耗时了, 而且key一旦丢了, 就GG了. 而且数据库服务器通常不会对外提供服务, 即使对外提供服务,也有权限验证的. 总的来说,数据库层加密有丢丢鸡肋.
但架不住有客户使用啊.... 由于使用者少, 遇到问题了就不好处理, 这里来记录一下加密表的常见错误及其处理过程.
我们知道mysql可以通过迁移表空间的方式来快速迁移数据, 非常的方便. 那么对于加密的表的迁移还会这么顺利么?
本次是在8.0.28环境模拟的, 可使用如下sql来构造数据, 对于
create table t20241112(id int primary key, name varchar(200)) ENCRYPTION='y';
insert into t20241112 values(1,'ddcw');
insert into t20241112 values(2,'https://github.com/ddcw/ibd2sql');
由于表空间迁移涉及到keyring file的问题, 我们就使用本地导出导入来模拟吧
-- 获取表结构
show create table t20241112;
-- 源端表空间导出
flush table t20241112 for export;
-- 拷贝到其它目录(ibd,cfg,cfp)
cp -ra /data/mysql_3314/mysqldata/db1/t20241112.* /tmp
-- 删除表
unlock tables;
drop table t20241112;
-- 创建表并导入数据
create table t20241112(id int primary key, name varchar(200)) ENCRYPTION='y';
alter table t20241112 discard tablespace;
cp -ra /tmp/t20241112.* /data/mysql_3314/mysqldata/db1
alter table t20241112 import tablespace;
这种其实通常是没得问题的
但有时候有的小伙伴会忘记拷贝.cfp
文件了, 就会遇到如下报错
ERROR 1808 (HY000): Schema mismatch (Table is in an encrypted tablespace, but the encryption meta-data file cannot be found while importing.)
报错说是没找到: 加密的元数据文件, 就是那个.cfp文件. 欸, 那我们再创建一个一样的表,做flush,并保留下cfg和cfp是否就可以了呢?, try it
重新生成cfp,并重新导入后报错如下
ERROR 1815 (HY000): Internal error: Cannot reset LSNs in table `db1`.`t20241112` : Data structure corruption
很遗憾, 并不行. 报错是数据结构有问题. 而我们的数据文件应该是没得问题的. 那问题在哪呢?
由于前面我们解析过keyring file文件, 知道了实际的key是放在表空间文件里面的, 而keyring file里面只是key的key, 而且可能轮转(我们这里没做过轮转,就不考虑轮转的场景了). 那我们对比下前后的cfp文件的差异吧,
发现确实有差异. 也就是每次做alter table tablename for export
生成的cfp文件内容是不一致的, 即要求cfp和ibd文件对应起来才能解析. 但我们现在的场景是不小心丢了cfp文件, 那么就永远无法恢复数据了么. keyring file都还在的啊! 欸嘿, 我们前面有一章讲过加密的ibd文件怎么解析(赶兴趣的自己去翻). 也就是我们还可以直接解析这个加密的ibd文件来恢复数据.
首先是下载ibd2sql,
wget https://github.com/ddcw/ibd2sql/archive/refs/heads/main.zip
unzip main.zip
cd ibd2sql-main
然后是提取出DDL和数据. (虽然DDL可以找业务测要, 但我们还是自己动手,丰衣足食)
python3 main.py /tmp/t20241112.ibd
看来是识别到这个ibd文件是加密的了, 要求我们提供keyring file.
python3 main.py /tmp/t20241112.ibd --keyring-file /usr/local/mysql/keyring/keyring
如果指定了错误的keyring文件的话, 也是会提示的. 所以keyring文件千万别整丢了!!!
python3 main.py /tmp/t20241112.ibd --keyring-file /usr/local/mysql/keyring/keyring2
看来是解析正确了. 那来瞅瞅数据呢
python3 main.py /tmp/t20241112.ibd --keyring-file /usr/local/mysql/keyring/keyring2 --sql
吼吼, 数据也是没得问题的.
即最后10字节会加上前面正常加密的22字节(cbc要求iv,所以要2个block(2*16),即一共32字节) (38--16374:aes:cbc + -32:aes:cbc:-10)
对于原理性的东西,兴趣不大, 就简单画个示意图吧:
我们只解析index page, 对于index page而言,最后10字节用处不大.(page_dir0:2 + checksum:4 + lsn:4)
吐槽下甲方的工时饱和度要求, 算了,牛马不配...
参考:
https://dev.mysql.com/doc/refman/8.0/en/innodb-data-encryption.html
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。