惊呆了!不改一行 Java 代码竟然就能轻松解决敏感信息加解密
云栖号资讯:【点击查看更多行业资讯】
在这里您可以找到不同行业的第一手的上云资讯,还在等什么,快来!
出于安全考虑,现需要将数据库的中敏感信息加密存储到数据库中,但是正常业务交互还是需要使用明文数据,所以查询返回我们还需要经过相应的解密才能返回给调用方。
ps:日常开发中,我们要有一定的安全意识,对于密码,金融数据等敏感信息事实加密存储保护。
这个需求说起来不是很难,我们只需要在执行 sql 之前,提前将指定数据进行加密。执行 sql 之后,获取返回结果,再进行的相应的解密。稍微改造下原有代码,很快完成需求。
现有加密算法如 RSA2 ,AES 等,密文长度将会是明文好几倍。上线加解密方案一定要评估数据库现有字段长度是否满足加密之后长度。
如果这是一张新建的表,上面的实现方案并没有什么问题。但是这次我们改造是几张已有已有千万级的存量的数据的表,这些数据都未被加密存储。
如果使用上述代码,使用加密之后的密文信息查询历史数据,当然查询不到任何结果。另外当查询返回的结果是明文,解密明文数据库也可能会导致相应的解密错误。
所以为了兼容历史数据,需要进行如下改造:
- 增加新字段存放对应的加密数据,sql 等值条件查询修改成 in 查询
- 查询返回的记录首先判断是否是密文,如果是密文再去解密
代码改造如下:
上述代码虽然解决业务需求,但是这个解决方案不是很优雅,业务代码改动较大,加解密的代码不能通用,所有涉及到相关字段的方法都需要改动,且几乎都是重复代码,代码侵入性很强,不是很友好。
有经验的同学可能会想到使用 Spring AOP 解决上述问题。
在切面的前置方法(beforeMethod)统一拦截查询参数,配合自定义的注解,加密指定的字段。
然后在切面的后置方法(afterReturn)拦截返回值,配合自定义注解,解密指定的字段。
Spring AOP 代码实现比较复杂,这里就不贴出具体的代码。
但是 Spring AOP 方案也并不通用,如果其他的应用也有相同的需求,同样的代码,又需要重复实现,还是很费时费力。
最终我们参考一个 github 开源项目『typehandlers-encrypt』,借助 mybatis 的 TypeHandler,实现通用的数据加解密解决方案。使用方只需要引入相关依赖,无需改动一行业务代码,仅需少量配置即可实现指定字段加解密操作,省时省力。
实现原理
mybatis 利用内置类型转换器(typeHandler),实现 Java 类型与 JDBC 类型的相互转换,我们正好可以利用这个特性,在转换之前加入加解密步骤。
typeHandler 底层原理不是复杂,如果我们没有使用 Mybatis,而是直接使用最原始的 JDBC 执行查询语句,相关代码如下:
我们需要手动判断 Java 类型,然后调用 PreparedStatement设置合适类型参数。获取返回结果之后,又需要手动调用 ResultSet 结果集获取相应类型的数据,这个过程十分繁琐。
使用 mybatis 之后,上述步骤就无需我们再实现了。mybatis 可以通过识别 Java/JDBC 类型,调用相应typeHandler,自动实现转换逻辑。
下图为 mybatis 内置类型转换器,基本涵盖了所有 Java/JDBC 数据类型。
通用解决方案
自定义 typeHandler
下面我们来实现带有加解密功能的类型转换器,实现方式也比较简单,只要继承 org.apache.ibatis.type.BaseTypeHandler,重写相关方法。
简单起见,上述加解密仅使用了 Base64,大家可以替换成相应加解密算法即或者引入相应加解密服务。
其中加密转换将在 setNonNullParameter 中执行,解密转换将在 getNullableResult中执行。
CryptTypeHandler 使用一个 MappedTypes 注解,包含一个 CryptType 类,这个类使用 mybatis 别名功能,可以极大简化 sqlmap 相关配置。
注册 typeHandler
使用方必须将 typeHandler 和 alias 注册到 mybatis 中,否则无法生效。
下面提供三种方式,可以根据项目情况选择其中一种即可:
单独使用 mybatis
这种场景需要在 mybatis-config.xml 配置,mybatis 启动时将会加载该配置文件。
使用 Spring 配置 Mybatis Bean
配合 Spring 使用时需要将 typeHandler 注入 SqlSessionFactoryBean ,配置方式如下:
SpringBoot
SpringBoot 方式就最简单了,只要引入 mybatis-starter,配置文件加入如下配置即可:
修改 mapper sql 配置
最后我们只要简单修改 mapper 中 resultMap 或 sql s配置就可以实现加解密。
假设我们对现有一张 bank_card 表进行加解密,表结构如下:
insert 加密
现需要对 card_no,phone,name,id_no 进行加密,insert 语句加密示例:
INSERT INTO bank_card (card_no, phone,name,id_no) VALUES (#{card_no,javaType=crypt}, #{phone,typeHandler=org.demo.type.CryptTypeHandler}, #{name,javaType=crypt}, #{id_no,javaType=crypt})
我们只需要在 #{} 指定 typeHandler,传入参数最后将被加密。使用 typeHandler需要使用类的全路径,比较繁琐,我们可以使用 javaType 属性,直接使用上面我们的定义别名 crypt。
数据库最终执行sql 如下:
INSERT INTO bank_card (card_no, phone,name,id_no) VALUES ('NjQzMjEyMzEyMzE=', 'MTM1Njc4OTEyMzQ=', '5rWL6K+V5Y2h', 'MTIzMTIzMTIzMQ==');
查询加解密
普通查询解密示例如下:
<result property="card_no" column="card_no" typeHandler="org.demo.type.CryptTypeHandler"/> <result property="name" column="name" typeHandler="org.demo.type.CryptTypeHandler"/> <result property="id_no" column="id_no" typeHandler="org.demo.type.CryptTypeHandler"/> <result property="phone" column="phone" typeHandler="org.demo.type.CryptTypeHandler"/>
select * from bank_card where id=#{id}
这里我们在 select 配置中只能使用 resultMap 属性,指定 typeHandler 。
数据库明文、密文共存的情况,查询解密示例如下:
最后我们可以将自定义的 typeHandler 单独打包发布,其他业务方只需要引用,改造相关配置文件,即可完成数据加解密。
总结
借助于自定义的 typeHandler,我们实现了一个通用的加解密的方案,该方案对于使用方来说代码侵入性小,开箱即用,可以快速完成加解密的改造。
【云栖号在线课堂】每天都有产品技术专家分享!
课程地址:https://yqh.aliyun.com/zhibo立即加入社群,与专家面对面,及时了解课程最新动态!
【云栖号在线课堂 社群】https://c.tb.cn/F3.Z8gvnK
原文发布时间:2020-04-09
本文作者:楼下小黑哥
本文来自:“掘金”,了解相关信息可以关注“掘金”
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
2020年春招过半,iOS开发面试题清单,带你高效刷题!
简述 最近收集梳理了一些iOS相关的问题,其中大部分都是大厂面试或者面试其他人用到的,能命中大部分的面试和日常工作,更希望你可以用它来检验自己 由于问题量太大,本文只是给了问题,希望发挥圈友的动手能力,自己去探索下,也可以在下方进行评论回复你的答案或者提出更高质量的问题!!! runtime相关问题 runtime是iOS开发最核心的知识了,如果下面的问题都解决了,那么对runtime的理解已经很深了。runtime已经开源了,这有一份别人调试好可运行的源码objc-runtime,也可以去官网找objc4 结构模型 介绍下runtime的内存模型(isa、对象、类、metaclass、结构体的存储信息等) 为什么要设计metaclass class_copyIvarList & class_copyPropertyList区别 class_rw_t 和 class_ro_t 的区别 category如何被加载的,两个category的load方法的加载顺序,两个category的同名方法的加载顺序 category & extension区别,能给NSObject添加...
- 下一篇
Docker+k8s 容器云建设中 10 个常见难点
随着云计算、DevOps和微服务应用架构的发展,容器云成为IT的主要基础设施平台之一。以Docker为代表的容器技术,是目前有效的应用交付模式之一;以Kubernetes为代表的容器编排技术,是目前流行的应用部署方案。云平台的基础设施、DevOps的工程体系和微服务应用架构是IT技术转型的底座。而容器云又是这个底座下的一块基石。 下面几个问题是在Docker+K8S容器云建设过程中,最常被问起和需要解决的难点问题。来自社区交流活动,多位社区会员分享解答,整理者:gavin_zhang 1、企业是应该选择原生的Docker还是定制化的Docker,比如胖容器/富容器? 【问题描述】Docker是当前企业在进行容器化时首选的容器技术,但是原生的Docker在实际使用的过程中,特别是在传统虚机运维到容器化运维的过渡中,会碰到以下类似问题: 1、如何ssh登录到容器,像登录虚机那样,可以通过ssh进行管理 2、对于普通用户来说,如何从容器中拷贝文件到外部 3、虚机中一般会配置定时任务,在容器中如何实现 4、虚机中一般会安装各种agent,容器中怎么去安装 若企业直接采用原生的Docker,那么...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Docker安装Oracle12C,快速搭建Oracle学习环境
- CentOS8安装Docker,最新的服务器搭配容器使用
- Windows10,CentOS7,CentOS8安装Nodejs环境
- CentOS7编译安装Cmake3.16.3,解决mysql等软件编译问题
- Linux系统CentOS6、CentOS7手动修改IP地址
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- SpringBoot2整合Thymeleaf,官方推荐html解决方案
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- Eclipse初始化配置,告别卡顿、闪退、编译时间过长
- MySQL8.0.19开启GTID主从同步CentOS8