一、前言
近几年来,无论对互联网公司还是传统行业,数据安全一直是企业绕不开的话题。而数据加密是数据安全领域最核心的模块之一。涉及客户安全数据或者一些商业性敏感数据,如身份证号、手机号、卡号、客户号等个人信息按照相关部门规定,都需要进行数据加密。这对安全部门以及业务团队都带来了巨大的挑战。
二、挑战
在真实业务场景中,相关业务开发团队则往往需要针对公司安全部门需求,自行实行并维护一套加解密系统, 如加解密SDK、或加解密服务提供的OpenAPI。然而真正实施过程中会发现有很多让人头疼的问题,如业务代码入侵严重,已上线的业务改造成本大,风险高等等。而彩虹桥针对这些痛点,提供了一套完整的透明化解决方案,实现了业务代码0入侵,安全低风险地无缝进行加密改造。下面我们就来剖析一下整个方案的实现原理。
主要针对不熟悉彩虹桥的同学,这里做一下简单介绍。彩虹桥用一句话概括就是基于Apache ShardingSphere二次开发的透明化数据库中间件,通过数据分片、读写分离、影子库、加解密等能力对原有数据库进行增强。目前得物内部主要采用的中心化部署架构和非中心化部署2种方式。
想进一步了解彩虹桥的同学,可以参考我之前写的一篇文章:得物数据库中间件平台“彩虹桥”演进之路
中心化部署架构(Proxy模式)
Proxy模式下,加解密实现模块是在Proxy内部完成,对上层应用完全透明。
去中心化部署(JDBC模式)
JDBC模式下,加解密实现模块是在Rainbow内部完成,对上层应用完全透明。
名词 | 解释 |
逻辑列 | 用于计算加解密列的逻辑名称,是业务代码中定义的SQL对应的列名称。 |
密文列 | 用于存储加密后的数据,是DB中实际存在的真实列名 |
明文列 | 存储明文的列,用于在加密数据迁移过程中仍旧提供服务,在洗数结束后可以删除。 |
-- 业务代码中的SQL
select phone from t_user where phone = '10086'
-- 经过彩虹桥改写后实际去数据库执行的SQL
select phone_cipher as phone from t_user where phone_cipher = 'xxx'
其中phone为逻辑列,phone_cipher为密文列,彩虹桥内部把10086经过加密后,把where条件改成phone_cipher = 'xxx',这里实际查询的是密文列,但是整个上层是无感知的,对业务来说这个字段就是phone,实际查询的数据库列是phone_cipher。
主要是用于告诉彩虹桥哪个逻辑表里哪个列用于存储密文数据(密文列)、使用什么算法加解密、哪个列用于存储明文数据(明文列)以及用户想使用哪个列进行 SQL 编写(逻辑列),在结合上面的例子看,规则配置就应该是这样的。
这里的明文列可能比较难理解,这里单独解释一下,明文列主要用于在加密数据迁移过程中仍旧提供服务,在洗数结束后可以删除。因为已上线业务改造前,数据库里面存储的只有明文,在改造过程前几个阶段查询所用列都是明文列。一般来说明文列可以与逻辑列保持一致。
新上线业务由于一切从零开始,不存在历史数据清洗问题,所以相对简单。只需要配置好规则,数据层不需要只需要保留一个密文列即可。
下面我们把整套解决方案拆分成几个阶段来逐个分析。
第一阶段(步骤1~8)- 增量数据双写(明文列、密文列同时维护)、存量数据清洗
举个例子:
-- 查询 --
-- 业务代码中的SQL
select phone from t_user where phone = '10086'
-- 这个阶段查询不需要改写SQL
select phone from t_user where phone = '10086'
-- 更新 --
-- 业务代码中的SQL
update t_user set phone = '10000' where id = 1
-- 经过彩虹桥改写后实际去数据库执行的SQL
update t_user set phone = '10000', phone_cipher = 'xxx' where id = 1
update t_user set phone_cipher = 'xxx',modify_time = modify_time
where id = 1 and phone = '10086'
第二阶段(步骤9~11)- 查明文列切换成查密文列
举个例子:
-- 查询 --
-- 业务代码中的SQL
select phone from t_user where phone = '10086'
-- 经过彩虹桥改写后实际去数据库执行的SQL
select phone_cipher as phone from t_user where phone_cipher = 'xxx'
-- 更新 --
-- 业务代码中的SQL
update t_user set phone = '10000' where id = 1
-- 经过彩虹桥改写后实际去数据库执行的SQL
update t_user set phone = '10000', phone_cipher = 'xxx' where id = 1
第三阶段(步骤12~14)- 停止写明文列,只写密文列
举个例子:
-- 查询 --
-- 业务代码中的SQL
select phone from t_user where phone = '10086'
-- 经过彩虹桥改写后实际去数据库执行的SQL
select phone_cipher as phone from t_user where phone_cipher = 'xxx'
-- 更新 --
-- 业务代码中的SQL
update t_user set phone = '10000' where id = 1
-- 经过彩虹桥改写后实际去数据库执行的SQL
update t_user set phone_cipher = 'xxx' where id = 1
第四阶段(步骤15)- 数据层明文列清洗
加密字段无法支持查询不区分大小写功能;
加密字段无法支持比较操作,如:大于、小于、ORDER BY、BETWEEN、LIKE 等;
加密字段无法支持计算操作,如:AVG、SUM 以及计算表达式。
密钥动态替换
数据加密是为了防止脱库时一些敏感字段泄露,那如果密钥泄露了,即使做了加密也是徒劳。所以密钥支持动态替换,整个数据安全等级会更上一层楼。具体的实现方式其实也比较简单,就是在密文中嵌入版本号信息,解密的时候根据版本号去匹配对应的密钥即可,同步清洗老版本的密文列即可。
加盐加密
活动推荐
主题:
得物无线技术沙龙(第三期)
时间:
12月4日 14:00 - 18:00
报名方式:
更多详情,请点击「沙龙详情」