0%

项目中敏感数据加解密的实践

导语

背景
由滴滴事件引发国家对数据安全的一系列反应,为贯彻国家的政策、维护数据的安全,我们公司也开始着手对系统中存储的敏感数据进行加密。
目前我们组管理的系统包含敏感数据字段包括:姓名、证件号、电话、邮箱、住址等。
国家层面

  • 数据安全保障能力是国家竞争力的直接体现;
  • 数据保护与安全是国家安全的重要方面;
  • 数据安全有序是数字经济健康发展的基础;
  • 数据安全是国家数字治理的重要议题。

企业层面

  • 数据安全保障直接影响企业与客户的关系;
  • 数据安全在企业信息化建设中占据主导地位。

项目中的加解密流程

概述

1、搭建新库,与需要做加密的旧库建立主从关系;
2、同步数据;
3、数据由旧库向新库同步完成(接近 100%);
4、启动定时任务,从旧库取数据,在程序中进行加密,按照 id
更新到新库;(保证幂等)
5、更新完成后,通过修改数据源配置切换到加密后的数据源;
6、部署上线包含加解密逻辑的业务代码。

流程图

image.png

补偿处理

由于数据量较大,采用分页进行加密,并用 redis 记录加密的最新页码,执行到某一页加密失败时,查明失败原因,修复程序,重新执行定时加密,此时加密的页码从出错页码开始执行,避免重头开始进行全量数据加密导致耗时。(如果要重头开始跑,可以通过输入指定参数清除 Redis 缓存重新跑全量加密)
对定时任务加密完成后,切换数据源上线加解密业务代码的期间的增量数据(未加密数据),仍旧可以通过启动定时任务加密。
image.png

多数据源配置

流程

1、自定义类 DynamicDataSource 继承 AbstractRoutingDatasource 类并注入 bean;
2、将所有数据源写入到 AbstractRoutingDatasource 类中;
3、以注解+切面的形式实现数据源的切换;
具体做法:
1)、在需要切换数据源的方法上标注注解,声明要切换后的数据源;
2)、执行到标注注解的方法时,通过切面获取到方法注解的 数据源名称;
3)、将数据源名称 set 进入当前线程中。
4、执行注解方法里的 mapper 时,AbstractRoutingDatasource.getConnection()方法调用
determineTargetDataSource(),该方法又调用 determineCurrentLookupKey()方法,获取
到第三步当前线程保存的数据源名称;
5、根据数据源 map 集合和作为 key 的数据源名称,获取到切换的数据源。
image.png
初始化数据源并注入到 bean 中
image.png

image.png

多数据源切换

使用注解+切面的方式实现数据源的动态切换

1
2
3
4
5
6
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CurDataSource {
String name() default "";
}

image.png

image.png

image.png

AbstractRoutingDatasource 核心代码

image.png

数据加解密的方式

SQL 函数实现加解密

采用 Mysql 内置的 AES 加解密函数,对某个字段进行加解密,如下。

1
2
3
4
5
6
-- 加密 张三
select HEX(AES_ENCRYPT(‘张三’,'ABC123!'));

-- 解密 张三
select AES_DECRYPT(UNHEX('B85BECE4E75D2AB848CD89BEAD6E2528'),'ABC123!');

使用场景:
需求小,指定加密内容,该方法可行。
密钥变 ,所有代码跟着变。
不推荐。

TypeHandler 实现

  • Mybatis 的类型转换器,可将 java 数据类型转换成与数据库适配的格式。

image.png

  • 加解密中的使用

自定义 EncryptionHandler 继承 BaseTypeHandler,重写里面的 setNonNullParameter 和 getNonableResult 方法,在敏感数据入库前做加密处理,在敏感数据出库时做解密处理。

  • 加密

image.png
image.png

  • 解密

image.png

image.png