一、背景

在我们数据库中有些时候会保存一些用户的敏感信息,比如: 手机号、银行卡等信息,如果这些信息以明文的方式保存,那么是不安全的。假如: 黑客黑进了数据库,或者离职人员导出了数据,那么就可能导致这些敏感数据的泄漏。因此我们就需要找到一种方法来解决这个问题。

二、解决方案

由于我们系统中使用了Mybatis作为数据库持久层,因此决定使用MybatisTypeHandlerPlugin来解决。

  • TypeHandler : 需要我们在某些列上手动指定 typeHandler 来选择使用那个typeHandler或者根据@MappedJdbcTypes 和 @MappedTypes注解来自行推断。

    • <result column="phone" property="phone" typeHandler="com.huan.study.mybatis.typehandler.EncryptTypeHandler"/>
  • Plugin : 可以拦截系统中的 select、insert、update、delete等语句,也能获取到sql执行前的参数和执行后的数据。

经过考虑,决定使用TypeHandler来加解密数据。

三、需求

我们有一张客户表customer,里面有客户手机号(phone)和客户地址(address)等字段,其中客户手机号(phone)是需要加密保存到数据库中的。

1、在添加客户信息时,自动将客户手机号加密保存到数据中。

2、在查询客户信息时,自动解密客户手机号。

四、实现思路

1、编写一个实体类,凡是此实体类的数据都表示需要加解密的

public class Encrypt {
private String value; public Encrypt() {
} public Encrypt(String value) {
this.value = value;
} public String getValue() {
return value;
} public void setValue(String value) {
this.value = value;
}
}

2、编写一个加解密的TypeHandler

  • 设置参数时,加密数据。
  • 从数据库获取记录时,解密数据。
package com.huan.study.mybatis.typehandler;

import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.symmetric.AES;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
import org.apache.ibatis.type.MappedTypes; import java.nio.charset.StandardCharsets;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException; /**
* 加解密TypeHandler
*
* @author huan.fu 2021/5/18 - 上午9:20
*/
@MappedJdbcTypes(JdbcType.VARCHAR)
@MappedTypes(Encrypt.class)
public class EncryptTypeHandler extends BaseTypeHandler<Encrypt> { private static final byte[] KEYS = "12345678abcdefgh".getBytes(StandardCharsets.UTF_8); /**
* 设置参数
*/
@Override
public void setNonNullParameter(PreparedStatement ps, int i, Encrypt parameter, JdbcType jdbcType) throws SQLException {
if (parameter == null || parameter.getValue() == null) {
ps.setString(i, null);
return;
}
AES aes = SecureUtil.aes(KEYS);
String encrypt = aes.encryptHex(parameter.getValue());
ps.setString(i, encrypt);
} /**
* 获取值
*/
@Override
public Encrypt getNullableResult(ResultSet rs, String columnName) throws SQLException {
return decrypt(rs.getString(columnName));
} /**
* 获取值
*/
@Override
public Encrypt getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
return decrypt(rs.getString(columnIndex));
} /**
* 获取值
*/
@Override
public Encrypt getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
return decrypt(cs.getString(columnIndex));
} public Encrypt decrypt(String value) {
if (null == value) {
return null;
}
return new Encrypt(SecureUtil.aes(KEYS).decryptStr(value));
}
}

注意️:

  1. @MappedTypes:表示该处理器处理的java类型是什么。
  2. @MappedJdbcTypes:表示处理器处理的Jdbc类型。

3、sql语句中写法

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.huan.study.mybatis.mappers.CustomerMapper"> <resultMap id="BaseResultMapper" type="com.huan.study.mybatis.entity.Customer">
<id column="id" property="id"/>
<result column="phone" property="phone"/>
<result column="address" property="address"/>
</resultMap> <insert id="addCustomer">
insert into customer(phone,address) values (#{phone},#{address})
</insert> <select id="findCustomer" resultMap="BaseResultMapper">
select * from customer where phone = #{phone}
</select> </mapper>

SQL中没有什么特殊的写法。

4、配置文件中指定Typehandler的包路径

mybatis.type-handlers-package=com.huan.study.mybatis.typehandler

5、编写后台代码

  1. 提供一个添加方法
  2. 提供一个根据手机号查询的方法

后台代码比较简单,直接查看 https://gitee.com/huan1993/spring-cloud-parent/tree/master/mybatis/mybatis-typehandler-encrypt
贴一个mapper层的截图。

6、测试结果


从测试结果中可知,添加数据时,需要加密的数据(phone)在数据库中已经加密了,在查询的时候,加密的数据已经自动解密了。

五、实现代码

后台代码: https://gitee.com/huan1993/spring-cloud-parent/tree/master/mybatis/mybatis-typehandler-encrypt

六、参考文档

1、https://mybatis.org/mybatis-3/zh/configuration.html#typeHandlers

2、https://github.com/mybatis/spring-boot-starter

使用Mybatis的TypeHandler加解密数据的更多相关文章

  1. 微信公众号-加解密数据demo坑

    demo里面的MsgSignature作为url参数一部分了,demo也不更新下 坑爹的微信! 解密信息部分 include_once "wxBizMsgCrypt.php"; $ ...

  2. T-SQL问题解决集锦——数据加解密

    原文:T-SQL问题解决集锦--数据加解密 以下代码已经在SQLServer2008上的示例数据库测试通过 问题一:如何为数据进行加密与解密,避免使用者窃取机密数据? 对于一些敏感数据,如密码.卡号, ...

  3. java安全与加解密

    1 安全 安全性相关内容分为认证.授权和审计(发现安全问题时可以查看相关历史记录) 用户认证 java API表示主体的是javax.security.auth.Subject类型,表示用户身份标识的 ...

  4. 痞子衡嵌入式:SNVS Master Key仅在i.MXRT10xx Hab关闭时才能用于DCP加解密

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是i.MXRT系列中数据协处理器DCP使用SNVS Master Key加解密的注意事项. i.MXRT不仅仅是处理性能超强的MCU,也是 ...

  5. Mybatis使用TypeHandler实现数据的加解密转换

    参考: MyBatis之TypeHandler: https://www.cnblogs.com/yulinfeng/p/5991170.html   前段时间收到这么个需求:为安全起见,要求在数据库 ...

  6. 从零开始实现一个MyBatis加解密插件

    作者:vivo 互联网服务器团队- Li Gang 本篇文章介绍使用MyBatis插件来实现数据库字段加解密的过程. 一.需求背景 公司出于安全合规的考虑,需要对明文存储在数据库中的部分字段进行加密, ...

  7. 以Crypto++实现RSA加解密二进制数据

    网上一大片讲怎么加解密字符串的,找了大半天也没找到讲加解密二进制数据的,于是自己研究了下,分享给大家. 加解密函数: #include <rsa.h> #include <randp ...

  8. T-SQL问题解决集锦——数据加解密(2)

    原文:T-SQL问题解决集锦--数据加解密(2) 问题三.如何让指定用户可以对数据表进行Truncate操作? Truncate在对大表全删除操作时,会明显比Delete语句更快更有效,但是因为它不需 ...

  9. 使用JDK中的安全包对数据进行加解密

    本文以使用DES对称加密算法为例使用jdk对数据进行加密解密. 首先需要了解Provider类,它是jdk引入的密码服务提供者概念,实现了Java安全性的一部分或者全部.Provider 可能实现的服 ...

随机推荐

  1. FTP协议简介

    1. FTP协议概述 FTP协议的英文全称为File Transfer Protocol, 简称为FTP, 它是从一个主机向一个主机传输文件的协议. FTP协议中客户端和服务器进行文件交互的方式如下图 ...

  2. golang sync.noCopy 类型 —— 初探 copylocks 与 empty struct

    问题引入 学习golang(v1.16)的 WaitGroup 代码时,看到了一处奇怪的用法,见下方类型定义: type WaitGroup struct { noCopy noCopy ... } ...

  3. expression动态构成

    http://blog.csdn.net/tastelife/article/details/7340205 http://blog.csdn.net/tastelife/article/detail ...

  4. Linux上安装服务器监视工具,名为pyDash。

    pyDash – A Web Based Linux Performance Monitoring Tool 你可以通过以下命令来判断是否已安装: pip --version # Python2.x ...

  5. Spring Boot 2.x 之 Logging

    [源起] 最近在看Apollo的源码,发现其all-in-one项目的脚本demo.sh在执行的时候,竟然没有向控制台输出Spring Boot的日志. 我们修改后构建的Fat Jar,在启动时却打印 ...

  6. win10连接mysql提示:ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES)

    win10中cmd连接mysql提示:ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YE ...

  7. php curl 发送post请求

    PHP curl_init函数 resource curl_init ([ string $url = NULL ] ) 初始化一个新的会话,返回一个cURL句柄,供curl_setopt(), cu ...

  8. adb devices如何连逍遥模拟器的设备

    adb device连接真机,上一篇已经讲过了,这篇讲如何连接模拟器.这里我用的模拟器逍遥模拟器.我先插上手机,另外启动了一个模拟器,直接在cmd中输入adb devices,按理应该有2个设备id, ...

  9. ARC122C-Calculator【乱搞,构造】

    正题 题目链接:https://atcoder.jp/contests/arc122/tasks/arc122_c 题目大意 一个数对开始是\((0,0)\),每次可以选择一个数加一或者让一个数加上另 ...

  10. Filter和Interceptor

    Filter的使用 拦截user下的所有请求 @WebFilter("/user/*") public class UserFilter implements Filter { @ ...