当前位置: 首页 > news >正文

MONI后台管理系统-数据敏感字段存储加密

前言:
    在我们数据库中,存在很多的敏感数据,如用户表中,存在用户电话、身份证号、邮箱等属于用户的敏感信息,我们通常在存入数据库后,将其进行加密存储,以此来保证数据安全性。
    加密的方式有很多,如摘要加密、对称加密、非对称加密等,这里不做描述。因为我们的数据加密存储后,查询出来还需解密进行显示,我们使用对称加密的方式来实现加密。
    常用的对称加密有DES、AES、3DES以及国密算法SM4等。前者我们比较推荐使用AES,那么我们这次的对称加密实现将使用Aes以及SM4。
    而对于代码来说,我们在存储时需要加密,查询时又需要解密,如果每个方法我们都去这样操作,冗余代码会非常的多,是非常不合适的。因为我们集成的是Mybatis-plus框架,我们可以自定义TypeHandler字段类型处理器来实现我们这一需求。类型处理器(TypeHandler)扮演着 JavaType 与 JdbcType 之间转换的桥梁角色。它们用于在执行 SQL 语句时,将 Java 对象的值设置到 PreparedStatement 中,或者从 ResultSet 或 CallableStatement 中取出值。在类型处理器中,我们针对特定字段集成加解密的逻辑即可。
    本项目代码已上传至gitee Omni-Admin

1. 定义EncryptHandler字段类型处理器。

package com.omni.admin.mybatis;import com.omni.admin.context.SpringContext;
import com.omni.admin.encryption.EncryptionTypeEnum;
import com.omni.admin.encryption.symmetricalencryption.SymmetricalEncryption;
import com.omni.admin.encryption.symmetricalencryption.SymmetricalEncryptionFactory;
import com.omni.admin.properties.EncryptionProperties;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;/*** 数据加解密拦截*/
public class EncryptHandler extends BaseTypeHandler<String> {@Overridepublic void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {ps.setString(i, encrypt(parameter));}@Overridepublic String getNullableResult(ResultSet rs, String columnName) throws SQLException {return decrypt(rs.getString(columnName));}@Overridepublic String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {return decrypt(rs.getString(columnIndex));}@Overridepublic String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {return decrypt(cs.getString(columnIndex));}/*** 加密*  */private String encrypt(String params){EncryptionProperties encryptionProperties = SpringContext.getBean(EncryptionProperties.class);Boolean enableStorage = encryptionProperties.getEnableStorage();if (Boolean.FALSE.equals(enableStorage)) return params;SymmetricalEncryption symmetricalEncryption = getSymmetricalEncryption(encryptionProperties.getStorageEncryption());return symmetricalEncryption.encrypt(params);}/*** 解密*/private String decrypt(String params){EncryptionProperties encryptionProperties = SpringContext.getBean(EncryptionProperties.class);Boolean enableStorage = encryptionProperties.getEnableStorage();if (Boolean.FALSE.equals(enableStorage)) return params;SymmetricalEncryption symmetricalEncryption = getSymmetricalEncryption(encryptionProperties.getStorageEncryption());return symmetricalEncryption.decrypt(params);}private SymmetricalEncryption getSymmetricalEncryption(EncryptionTypeEnum encryptionTypeEnum){return SymmetricalEncryptionFactory.getSymmetricalEncryption(encryptionTypeEnum);}
}

2. 使用该处理器

我们以用户实体为例,当中有电话、身份证号和你邮箱。在@TableField注解中,加入EncryptHandler类型处理器即可。另外还需在@TableName注解中,添加autoResultMap = true属性,这样在查询时才能进行解密。

@EqualsAndHashCode(callSuper = true)
@Data
@TableName(value = "omni_user_info",autoResultMap = true)
public class UserInfo extends BaseEntity {/*** 用户电话*/@Sensitize(rule = SensitizeRuleEnums.MOBILE_PHONE)@TableField(value = "F_PHONE",typeHandler = EncryptHandler.class)private String phone;/*** 用户邮箱*/@TableField(value = "F_EMAIL",typeHandler = EncryptHandler.class)private String email;/*** 用户身份证*/@TableField(value = "F_ID_CARD",typeHandler = EncryptHandler.class)private String idCard;}

3. 查看效果

我们可在看到数据库中目前存储的就是密文了。
在这里插入图片描述

4. 加密的实现

这里我们考虑到设计以及后续的拓展性,我们对称加密的实现将会有多个,使用工厂模式来设计编码。

4.1 创建对称机密接口类SymmetricalEncryption

该接口空中提供了加密接口和解密接口,由子类去实现。

package com.omni.admin.encryption.symmetricalencryption;public interface SymmetricalEncryption {/*** 加密* @param plaintext 明文* @param key 密钥* @return 加密后的值*/String encrypt(String  plaintext, String key);/*** 加密* @param plaintext 明文* @return 加密后的值*/String encrypt(String  plaintext);/*** 解密* @param ciphertext 密文* @param key 密钥* @return 解密后的明文*/String decrypt(String ciphertext, String key);/*** 解密* @param ciphertext 密文* @return 解密后的明文*/String decrypt(String ciphertext);
}
4.2 AES加解密实现SymmetricalEncryptionAes类

maven依赖

        <dependency><groupId>org.bouncycastle</groupId><artifactId>bcprov-jdk15on</artifactId><version>1.70</version></dependency>
4.3 加解密工具类EncryptUtils
package com.omni.admin.utils;import com.omni.admin.exception.ExceptionStatus;
import com.omni.admin.exception.OmniException;
import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.Security;public class EncryptUtils {static{Security.addProvider(new BouncyCastleProvider());}private static final Logger log = LoggerFactory.getLogger(EncryptUtils.class);public static String sm4Encrypt(String plainString, String key) {return encrypt(plainString,key,"SM4");}public static String aesEncrypt(String plainString, String key) {return encrypt(plainString,key,"AES");}public static String sm4Decrypt(String plainString, String key) {return decrypt(plainString,key,"SM4");}public static String aesDecrypt(String plainString, String key) {return decrypt(plainString,key,"AES");}private static String encrypt(String plainString, String key,String algorithm) {try {// 创建密钥规范SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), algorithm);// 获取Cipher对象实例(BC中SM4默认使用ECB模式和PKCS5Padding填充方式,因此下列模式和填充方式无需指定)Cipher cipher = Cipher.getInstance(algorithm + "/ECB/PKCS5Padding");// 初始化Cipher为加密模式cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);// 获取加密byte数组byte[] cipherBytes = cipher.doFinal(plainString.getBytes(StandardCharsets.UTF_8));// 输出为Base64编码return Base64.encodeBase64String(cipherBytes);} catch (Exception e) {log.error(e.getMessage(), e);throw new OmniException(ExceptionStatus.ENCRYPT_ERROR);}}private static String decrypt(String ciphertext, String key,String algorithm) {try {// 创建密钥规范SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), algorithm);// 获取Cipher对象实例(Java8中AES默认使用ECB模式和PKCS5Padding填充方式,因此下列模式和填充方式无需指定)Cipher cipher = Cipher.getInstance(String.format("%s/ECB/PKCS5Padding", algorithm));// 初始化Cipher为解密模式cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);// 获取加密byte数组byte[] cipherBytes = cipher.doFinal(Base64.decodeBase64(ciphertext));// 输出为字符串return new String(cipherBytes);} catch (Exception e) {log.error(e.getMessage(), e);throw new OmniException(ExceptionStatus.ENCRYPT_ERROR);}}
}
package com.omni.admin.encryption.symmetricalencryption;
import com.omni.admin.utils.EncryptUtils;public class SymmetricalEncryptionAes implements SymmetricalEncryption {public static final String KEY = "cf410532f92a47de";@Overridepublic String encrypt(String plaintext, String key) {return EncryptUtils.aesEncrypt(plaintext,key);}@Overridepublic String encrypt(String plaintext) {return encrypt(plaintext, KEY);}@Overridepublic String decrypt(String ciphertext, String key) {return EncryptUtils.aesDecrypt(ciphertext,key);}@Overridepublic String decrypt(String ciphertext) {return decrypt(ciphertext, KEY);}
}
4.4 国密算法SymmetricalEncryptionSM4类
package com.omni.admin.encryption.symmetricalencryption;import com.omni.admin.utils.EncryptUtils;public class SymmetricalEncryptionSM4 implements SymmetricalEncryption {public static final String KEY = "cf410532f92a47de";@Overridepublic String encrypt(String plaintext, String key) {return EncryptUtils.sm4Encrypt(plaintext,key);}@Overridepublic String encrypt(String plaintext) {return encrypt(plaintext, KEY);}@Overridepublic String decrypt(String ciphertext, String key) {return EncryptUtils.sm4Decrypt(ciphertext,key);}@Overridepublic String decrypt(String ciphertext) {return decrypt(ciphertext, KEY);}
}
4.5 加解密工厂类SymmetricalEncryptionFactory
package com.omni.admin.encryption.symmetricalencryption;import com.omni.admin.encryption.EncryptionTypeEnum;
import com.omni.admin.exception.ExceptionStatus;
import com.omni.admin.exception.OmniException;public class SymmetricalEncryptionFactory {private SymmetricalEncryptionFactory() {}public static SymmetricalEncryption getSymmetricalEncryption(EncryptionTypeEnum encryptionType) {if (EncryptionTypeEnum.AES.equals(encryptionType)){return new SymmetricalEncryptionAes();}if (EncryptionTypeEnum.SM4.equals(encryptionType)){return new SymmetricalEncryptionSM4();}throw new OmniException(ExceptionStatus.NOT_FOUND_SIGNATURE);}
}
4.6 枚举类
package com.omni.admin.encryption;import lombok.Getter;@Getter
public enum EncryptionTypeEnum {MD5("md5"),SHA256("sha256"),SM3("sm3"),AES("AES"),SM4("SM4");private final String type;EncryptionTypeEnum(String type) {this.type = type;}
}

5. 加解密类型的配置化EncryptionProperties

package com.omni.admin.properties;import com.omni.admin.encryption.EncryptionTypeEnum;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;@Data
@Configuration
@ConfigurationProperties(prefix = "omni.encryption")
public class EncryptionProperties {/*** 是否开启数据签名*/private Boolean enableSign = true;/*** 是否开启存储加密*/private Boolean enableStorage = true;/*** 签名加密算法*/private EncryptionTypeEnum signAlgorithm = EncryptionTypeEnum.SM3;/*** 存储加密算法*/private EncryptionTypeEnum storageEncryption = EncryptionTypeEnum.SM4;
}

相关文章:

MONI后台管理系统-数据敏感字段存储加密

前言&#xff1a;     在我们数据库中&#xff0c;存在很多的敏感数据&#xff0c;如用户表中&#xff0c;存在用户电话、身份证号、邮箱等属于用户的敏感信息&#xff0c;我们通常在存入数据库后&#xff0c;将其进行加密存储&#xff0c;以此来保证数据安全性。     …...

熟悉各类游戏设计模式的用途与限制,如 factory、strategy、mvc、object pool 等

良好的系统分析与设计能力要求开发者熟悉并正确运用各种设计模式来解决特定问题。设计模式是一种针对特定问题的通用解决方案&#xff0c;可提高代码的可复用性、可维护性和可扩展性。以下是对一些常见游戏设计模式的详细分析&#xff0c;包括其用途、限制和代码示例。 一、工厂…...

【RabbitMQ高级篇】消息可靠性问题(1)

目录 1.消息可靠性 1.1.生产者消息确认 1.1.1.修改配置 1.1.2.定义Return回调 1.1.3.定义ConfirmCallback 1.2.消息持久化 1.2.1.交换机持久化 1.2.2.队列持久化 1.2.3.消息持久化 1.3.消费者消息确认 1.3.1.演示none模式 1.3.2.演示auto模式 1.4.消费失败重试机制…...

ASP.NET |日常开发中常见问题归纳讲解

ASP.NET &#xff5c;日常开发中常见问题归纳讲解 前言一、性能问题1.1 数据库访问性能1.2 视图状态&#xff08;在ASP.NET Web Forms 中&#xff09; 二、安全问题2.1 SQL 注入2.2 跨站脚本攻击&#xff08;XSS&#xff09; 三、状态管理问题3.1 会话状态&#xff08;Session …...

【【深入浅出TinyRisc-v】】

深入浅出TinyRisc-v 本代码参考于 https://gitee.com/liangkangnan/tinyriscv 自己理解之后又重新写了一遍 tinyriscv.v // 涓嬮潰鏄鏁翠釜top妯″潡鐨勪功鍐? module tinyriscv(input clk ,input rst_n …...

常见的限流算法

常见的限流算法 限流的定义固定窗口算法滑动窗口算法漏桶算法&#xff08;推荐&#xff09;令牌桶算法(推荐)限流粒度本地限流&#xff08;单机限流&#xff09;分布式限流&#xff08;多机限流&#xff09;分布式限流的实现 限流的定义 限流&#xff0c;也称流量控制。是指系统…...

【Leetcode 每日一题】3159. 查询数组中元素的出现位置

问题背景 给你一个整数数组 n u m s nums nums&#xff0c;一个整数数组 q u e r i e s queries queries 和一个整数 x x x。 对于每个查询 q u e r i e s [ i ] queries[i] queries[i]&#xff0c;你需要找到 n u m s nums nums 中第 q u e r i e s [ i ] queries[i] q…...

xadmin后台首页增加一个导入数据按钮

xadmin后台首页增加一个导入数据按钮 效果 流程 1、在添加小组件中添加一个html页面 2、写入html代码 3、在urls.py添加导入数据路由 4、在views.py中添加响应函数html代码 <!DOCTYPE html> <html lang...

行为树详解(5)——事件驱动

【分析】 如果行为树的节点很多&#xff0c;那么会存在要经过很多节点才会走到动作节点的情况。显然&#xff0c;性能上不如状态机。 每帧都需要重新遍历一系列节点才会走到动作节点&#xff0c;而实际上很多条件节点在数帧内不会有变化&#xff0c;这是造成性能问题的重要原…...

3.若依前端项目拉取、部署、访问

因为默认RuoYi-Vue是使用的Vue2,所以需要另外去下载vue3来部署。 拉取代码 git clone https://gitee.com/ys-gitee/RuoYi-Vue3.git 安装node才能执行npm相关的命令 执行命令npm install 如果npm install比较慢的话&#xff0c;需要添加上国内镜像 npm install --registrhttp…...

Debian操作系统相对于Ubuntu有什么优势吗?

更高的稳定性&#xff1a;Debian 以其出色的稳定性闻名&#xff0c;得益于严格的软件包测试和发布流程。其稳定版经过长时间测试与验证&#xff0c;确保了系统的高度稳定&#xff0c;更适合对稳定性要求极高的长期运行服务器环境。而 Ubuntu 虽有稳定版本&#xff0c;但更新周期…...

【漏洞复现】CVE-2015-3337 Arbitrary File Reading

漏洞信息 NVD - CVE-2015-3337 Directory traversal vulnerability in Elasticsearch before 1.4.5 and 1.5.x before 1.5.2, when a site plugin is enabled, allows remote attackers to read arbitrary files via unspecified vectors. 在安装了具有“site”功能的插件以…...

win10、win11-鼠标右键还原、暂停更新

系统优化 win 10jihuo win 11jihuo鼠标右键还原暂停更新 update 2024.12.28win 10 jihuo winx&#xff0c;打开powershell管理员&#xff0c;输入以下命令,选择1并等待 irm https://get.activated.win | iex参考&#xff1a;https://www.bilibili.com/video/BV1TN411M72J/?sp…...

FFmpeg来从HTTP拉取流并实时推流到RTMP服务器

当使用FFmpeg来从HTTP拉取流并实时推流到RTMP服务器时&#xff0c;你可以使用以下命令&#xff1a; ffmpeg -i http://输入流地址 -c:v copy -c:a copy -f flv rtmp://RTMP服务器地址/应用名称/流名称 这是一个基本的命令示例&#xff0c;其中&#xff1a; - -i http://输入流地…...

Quo Vadis, Anomaly Detection? LLMs and VLMs in the Spotlight 论文阅读

文章信息&#xff1a; 原文链接&#xff1a;https://arxiv.org/abs/2412.18298 Abstract 视频异常检测&#xff08;VAD&#xff09;通过整合大语言模型&#xff08;LLMs&#xff09;和视觉语言模型&#xff08;VLMs&#xff09;取得了显著进展&#xff0c;解决了动态开放世界…...

Rust : tokio中select!

关于tokio的select宏&#xff0c;有不少的用途。包括超时和竞态选择等。 关于select宏需要关注&#xff0c;相关的异步条件&#xff0c;会同时执行&#xff0c;只是当有一个最早完成时&#xff0c;会执行“抛弃”和“对应”策略。 说明&#xff1a;对本文以下素材的来源表示感…...

【hackmyvm】hacked靶机wp

tags: HMVrootkitDiamorphine Type: wp 1. 基本信息^toc 文章目录 1. 基本信息^toc2. 信息收集2.1. 端口扫描2.2. 目录扫描2.3. 获取参数 3. 提权 靶机链接 https://hackmyvm.eu/machines/machine.php?vmHacked 作者 sml 难度 ⭐️⭐️⭐️⭐️️ 2. 信息收集 2.1. 端口扫描…...

MaixBit k210学习记录

开发背景&#xff1a;Window系统主机&#xff0c;在主机上安装了虚拟机&#xff08;VirtualBoxUbuntu23.04&#xff09; 目标实现&#xff1a;在虚拟机&#xff08;Ubuntu&#xff09;中&#xff0c;实现对Maix bit&#xff08;k210&#xff09;开发板的开发 虚拟机的安装参考…...

Wordperss漏洞 DeDeCMS漏洞

Wordperss漏洞 环境搭建 #执⾏命令 cd /vulhub/wordpress/pwnscriptum docker-compose up -d #靶场地址 http://8.155.7.173:8080/wp-admin/ 注册账号 登录 漏洞一&#xff1a;后台修改模板拿WebShell 步骤一&#xff1a;思路是修改其WP的模板写入⼀句话木马后门并访问其文件…...

如何构建有效的AI Agents:从复杂到简约——深度解读Claude实践总结《Building effective agents》(上)

在人工智能技术日新月异的今天&#xff0c;大语言模型(LLM)已经成为技术创新的热点。 然而&#xff0c;在追逐技术前沿的热潮中&#xff0c;我们是否忽视了工程设计的本质&#xff1f; 作为全球人工智能领域的领军企业之一&#xff0c;Anthropic以其在AI安全和伦理方面的深入…...

生成xcframework

打包 XCFramework 的方法 XCFramework 是苹果推出的一种多平台二进制分发格式&#xff0c;可以包含多个架构和平台的代码。打包 XCFramework 通常用于分发库或框架。 使用 Xcode 命令行工具打包 通过 xcodebuild 命令可以打包 XCFramework。确保项目已经配置好需要支持的平台…...

Java 语言特性(面试系列1)

一、面向对象编程 1. 封装&#xff08;Encapsulation&#xff09; 定义&#xff1a;将数据&#xff08;属性&#xff09;和操作数据的方法绑定在一起&#xff0c;通过访问控制符&#xff08;private、protected、public&#xff09;隐藏内部实现细节。示例&#xff1a; public …...

在HarmonyOS ArkTS ArkUI-X 5.0及以上版本中,手势开发全攻略:

在 HarmonyOS 应用开发中&#xff0c;手势交互是连接用户与设备的核心纽带。ArkTS 框架提供了丰富的手势处理能力&#xff0c;既支持点击、长按、拖拽等基础单一手势的精细控制&#xff0c;也能通过多种绑定策略解决父子组件的手势竞争问题。本文将结合官方开发文档&#xff0c…...

3.3.1_1 检错编码(奇偶校验码)

从这节课开始&#xff0c;我们会探讨数据链路层的差错控制功能&#xff0c;差错控制功能的主要目标是要发现并且解决一个帧内部的位错误&#xff0c;我们需要使用特殊的编码技术去发现帧内部的位错误&#xff0c;当我们发现位错误之后&#xff0c;通常来说有两种解决方案。第一…...

高频面试之3Zookeeper

高频面试之3Zookeeper 文章目录 高频面试之3Zookeeper3.1 常用命令3.2 选举机制3.3 Zookeeper符合法则中哪两个&#xff1f;3.4 Zookeeper脑裂3.5 Zookeeper用来干嘛了 3.1 常用命令 ls、get、create、delete、deleteall3.2 选举机制 半数机制&#xff08;过半机制&#xff0…...

【论文笔记】若干矿井粉尘检测算法概述

总的来说&#xff0c;传统机器学习、传统机器学习与深度学习的结合、LSTM等算法所需要的数据集来源于矿井传感器测量的粉尘浓度&#xff0c;通过建立回归模型来预测未来矿井的粉尘浓度。传统机器学习算法性能易受数据中极端值的影响。YOLO等计算机视觉算法所需要的数据集来源于…...

vue3 定时器-定义全局方法 vue+ts

1.创建ts文件 路径&#xff1a;src/utils/timer.ts 完整代码&#xff1a; import { onUnmounted } from vuetype TimerCallback (...args: any[]) > voidexport function useGlobalTimer() {const timers: Map<number, NodeJS.Timeout> new Map()// 创建定时器con…...

2025盘古石杯决赛【手机取证】

前言 第三届盘古石杯国际电子数据取证大赛决赛 最后一题没有解出来&#xff0c;实在找不到&#xff0c;希望有大佬教一下我。 还有就会议时间&#xff0c;我感觉不是图片时间&#xff0c;因为在电脑看到是其他时间用老会议系统开的会。 手机取证 1、分析鸿蒙手机检材&#x…...

【Java_EE】Spring MVC

目录 Spring Web MVC ​编辑注解 RestController RequestMapping RequestParam RequestParam RequestBody PathVariable RequestPart 参数传递 注意事项 ​编辑参数重命名 RequestParam ​编辑​编辑传递集合 RequestParam 传递JSON数据 ​编辑RequestBody ​…...

QT3D学习笔记——圆台、圆锥

类名作用Qt3DWindow3D渲染窗口容器QEntity场景中的实体&#xff08;对象或容器&#xff09;QCamera控制观察视角QPointLight点光源QConeMesh圆锥几何网格QTransform控制实体的位置/旋转/缩放QPhongMaterialPhong光照材质&#xff08;定义颜色、反光等&#xff09;QFirstPersonC…...