Springboot+dynamic-datasource+Druid数据库配置加密

news2024/11/16 16:00:50

Springboot+mybatis-plus+dynamic-datasource+Druid数据库配置加密

文章目录

  • 0.前言
  • 1. 动态添加移除数据源
  • 2.基础介绍
  • 3. 使用步骤示例
    • 简单方式,使用默认的加密
      • 1. 使用下面 工具类输出,加密后的密码
      • 1. 将上面加密后的密码配置到配置文件中
        • 如果使用的默认key,即上面生成加密后密码的第一种,则使用下面方式配置
        • 如果使用的自定义的key,即上面既生成publicKey和privateKey 以及加密后密码的第2种方式,则使用下面方式配置
  • 4. 官方源码分析
    • 5.1. 解密的核心源码
    • 5.2. 自定义解密
  • 5. 参考资料

0.前言

背景
生产环境中, 为了保密,我们希望将数据库密码加密, 甚至用户名和jdbc连接串加密。本章我们使用由苞米豆(baomidou)团队开发的dynamic-datasource多数据源组件自带的加密工具实现数据库配置加密
在这里插入图片描述

1. 动态添加移除数据源

dynamic-datasource-starter官方给的特性说明中,我们可以看到 dynamic-datasource-starter 支持数据库敏感配置信息 加密(可自定义) ENC()。,所以我们撸一下源码看看到底怎么实现的。
经过查看源码发现, 该框架使用自带的加密工具类com.baomidou.dynamic.datasource.toolkit.CryptoUtils进行加解密, 且自带有公钥私钥。但是源码咋看都觉得眼熟,而且注释是@author alibaba,翻看druid 的加密方法 com.alibaba.druid.filter.config.ConfigTools 。原来作者直接借鉴了Druid加密方法,之前看druid 的加密的时候发现公钥和私钥的使用反了,wenshao给的解释是历史原因。历史背景和源码咱们就聊到这,所以直接使用此工具类加密我们的明文密码, 然后用ENC()包裹即可实现加解密
在这里插入图片描述

2.基础介绍

在使用 Spring Boot、MyBatis-Plus、 Druid 进行数据库配置时,如果需要对敏感配置信息进行加密,可以通过以下方式实现:

  1. 使用加密算法对敏感信息进行加密,如数据库的用户名、密码等信息。可以选择对称加密算法(如AES)或非对称加密算法(如RSA)进行加密。
  2. 将加密后的敏感信息保存在安全的位置,如配置文件或系统环境变量。
  3. 在应用启动时,通过配置文件或环境变量读取加密后的敏感信息。
  4. 在配置动态数据源时,使用解密的敏感信息进行数据库配置。

这是基本的思路,本章我们不造轮子,直接使用国产优秀框架baomidou团队的工具 dynamic-datasource多数据源组件自带的加密工具实现数据库配置加密

3. 使用步骤示例

简单方式,使用默认的加密

1. 使用下面 工具类输出,加密后的密码

import com.baomidou.dynamic.datasource.toolkit.CryptoUtils;
public class DBCryptoUtils extends CryptoUtils{

        // 第一种方式 使用默认key 加密解密
        public static void test1( ) throws Exception {
            System.out.println("-------------------------------------默认加密-------------------------------------");
            String password = "abc123";
            String encodePassword = CryptoUtils.encrypt(password);
            System.out.println("加密后密码:"+CryptoUtils.encrypt(password));
        }
        // 第二种方式 使用自定义key,强烈建议
        public static void test2( ) throws Exception {
            System.out.println("-------------------------------------自定义key-------------------------------------");
            String[] pair = CryptoUtils.genKeyPair(512);
            System.out.println("privateKey:  " + pair[0]);
            System.out.println("publicKey:  " + pair[1]);
             // 按道理应该用公钥加密,私钥解密,作者直接抄的druid 的,把这个不规范的写法也给抄过来了,不影响效果,只觉得怪怪的。
            System.out.println("加密后密码:  " + CryptoUtils.encrypt(pair[0], "abc123"));
        }

        public static void main(String[] args) throws Exception {
            test1();
            test2();
        }
}

在这里插入图片描述

1. 将上面加密后的密码配置到配置文件中

如果使用的默认key,即上面生成加密后密码的第一种,则使用下面方式配置

spring:
  datasource:
    dynamic:
     #有默认值可以不配置,强烈建议更换
      public-key: 
      datasource:
        master:
          url: DB地址
          username: 用户名
          #配置加密后的密码
          password: ENC(Ue9QTmtvOX8XMdRIZVqUAbmbLNfAjQQO9jokfVEfaew+HFGZPndSmcq2pOTS2xuC7Pg/z1gUGS82HOmWw0d9Cw==)  
          driver-class-name: com.mysql.jdbc.Driver# 驱动保持jdbc url一致
          public-key: #在多数据源下每个数据源可以独立设置,没有就继承上面的。

如果使用的自定义的key,即上面既生成publicKey和privateKey 以及加密后密码的第2种方式,则使用下面方式配置

spring:
  datasource:
    dynamic:
     # 配置上面输出的 public key
      public-key: MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJirfs9pc4fsDdXqjMto4zY+sYZ7d/XYwIQIYqj2FoqxvVC61tjKtG12nMSlwgXbV+DNpWh9W76QjM2XCNYB6VUCAwEAAQ==
      datasource:
        master:
          url: DB地址
          username: 用户名
          #配置加密后的密码 根据上面生成的秘钥,加密后的密码
          password: ENC(BSbigK5YuTXLOUDekSm3uU+h/n2/rIwa4DxQWPbfuhf9irwoakQy777AYHqJVz/WEG5BTFp4Ym+lguH3o+f4kQ==)  
          driver-class-name: com.mysql.jdbc.Driver# 驱动保持jdbc url一致
          public-key: #在多数据源下每个数据源可以独立设置,没有就继承上面的。

到这儿基本上就OK了,如果想知道源码是怎么执行的可以继续向下看

4. 官方源码分析

5.1. 解密的核心源码

我们先来看EncDataSourceInitEvent 源码.我们可以看到EncDataSourceInitEvent类,实现了DataSourceInitEvent接口。该类用于在数据源初始化之前对数据源属性进行解密操作。

/**
 * 多数据源默认解密事件
 *
 * @author TaoYu
 */
@Slf4j
public class EncDataSourceInitEvent implements DataSourceInitEvent {

    /**
     * 加密正则
     */
    private static final Pattern ENC_PATTERN = Pattern.compile("^ENC\\((.*)\\)$");

    @Override
    public void beforeCreate(DataSourceProperty dataSourceProperty) {
        String publicKey = dataSourceProperty.getPublicKey();
        if (StringUtils.hasText(publicKey)) {
            dataSourceProperty.setUrl(decrypt(publicKey, dataSourceProperty.getUrl()));
            dataSourceProperty.setUsername(decrypt(publicKey, dataSourceProperty.getUsername()));
            dataSourceProperty.setPassword(decrypt(publicKey, dataSourceProperty.getPassword()));
        }
    }

    @Override
    public void afterCreate(DataSource dataSource) {

    }

    /**
     * 字符串解密
     */
    private String decrypt(String publicKey, String cipherText) {
        if (StringUtils.hasText(cipherText)) {
            Matcher matcher = ENC_PATTERN.matcher(cipherText);
            if (matcher.find()) {
                try {
                    return CryptoUtils.decrypt(publicKey, matcher.group(1));
                } catch (Exception e) {
                    log.error("DynamicDataSourceProperties.decrypt error ", e);
                }
            }
        }
        return cipherText;
    }
}

DataSourceInitEvent 接口 又是干什么用的呢,我们点进去可以看到
在这里插入图片描述

DataSourceInitEvent是 baomidou的dynamic.datasource组件 位于com.baomidou.dynamic.datasource.event包下定义的一个钩子接口,在创建连接池前和后可以搞事情。

  1. 该接口定义了两个方法:beforeCreateafterCreate,用于在连接池创建前后执行一些操作。
  2. beforeCreate方法接受一个DataSourceProperty参数,用于传递数据源的基本信息。
  3. afterCreate方法接受一个DataSource参数,表示已创建的连接池对象。

总之,这段代码是一个事件接口,用于在多数据源连接池创建过程中执行一些自定义操作。
让我们逐行解析代码的功能:

  1. 定义了一个名为ENC_PATTERN的正则表达式模式,用于匹配加密字符串的格式。

  2. 实现了beforeCreate方法,该方法在数据源创建之前调用。它接收一个DataSourceProperty对象作为参数,表示数据源的属性。

  3. beforeCreate方法中,首先获取数据源属性中的公钥(publicKey)。如果公钥存在,表示需要进行解密操作。

  4. 接下来,使用公钥对数据源的URL、用户名和密码进行解密操作。调用decrypt方法对这些属性进行解密,并将解密后的值设置回dataSourceProperty对象中。

  5. 实现了afterCreate方法,该方法在数据源创建之后调用。在该方法中可以执行一些额外的操作,但是该方法在给定的代码中没有实现任何逻辑。

  6. 定义了一个私有方法decrypt,用于对加密字符串进行解密。该方法接收公钥和密文作为参数,并返回解密后的明文字符串。

  7. decrypt方法中,首先判断密文是否符合加密格式(通过ENC_PATTERN进行匹配)。如果匹配成功,就使用给定的公钥和密文调用CryptoUtils.decrypt方法进行解密操作。

总结起来,EncDataSourceInitEvent类实现了DataSourceInitEvent接口,用于在数据源初始化之前对数据源属性进行解密操作。它通过正则表达式匹配加密字符串的格式,并使用给定的公钥对密文进行解密。解密后的明文值将用于设置数据源的URL、用户名和密码属性。

5.2. 自定义解密

到这儿我们可能,已经知道怎么自定义解密,无外乎就是实现DataSourceInitEvent 接口的beforeCreate方法然后自定义处理。但是我们自定义的这个实现类和官方默认的解密实现类优先级怎么搞呢,其实官方在DynamicDataSourceAutoConfiguration配置类中已经使用了@condition条件注解。满足优先使用我们自定义的加密的实现类了。我们只需要交给Spring 容器就OK.
在这里插入图片描述

在这里插入图片描述

/**
 * 自定义多数据源默认解密事件
 */
@Slf4j
@Configuration
public class CustomeEncDataSourceInitEvent implements DataSourceInitEvent {

    /**
     * 加密正则 实现自定义的 例如BCC
     */
    private static final Pattern ENC_PATTERN = Pattern.compile("^BCC\\((.*)\\)$");

    @Override
    public void beforeCreate(DataSourceProperty dataSourceProperty) {
    	// TODO 实现自定义的解密
        String publicKey = dataSourceProperty.getPublicKey();
        if (StringUtils.hasText(publicKey)) {
            dataSourceProperty.setUrl(decrypt(publicKey, dataSourceProperty.getUrl()));
            dataSourceProperty.setUsername(decrypt(publicKey, dataSourceProperty.getUsername()));
            dataSourceProperty.setPassword(decrypt(publicKey, dataSourceProperty.getPassword()));
        }
    }

    @Override
    public void afterCreate(DataSource dataSource) {

    }

    /**
     * 字符串解密
     */
    private String decrypt(String publicKey, String cipherText) {
        if (StringUtils.hasText(cipherText)) {
            Matcher matcher = ENC_PATTERN.matcher(cipherText);
            if (matcher.find()) {
                try {
                    return CryptoUtils.decrypt(publicKey, matcher.group(1));
                } catch (Exception e) {
                    log.error("DynamicDataSourceProperties.decrypt error ", e);
                }
            }
        }
        return cipherText;
    }
}

5. 参考资料

  1. dynamic-datasource GitHub 仓库 ↗:dynamic-datasource 的官方 GitHub 仓库,包含源代码、文档和示例等资源。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/921938.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

完全免费的GPT,最新整理,2023年8月24日,已人工验证,不用注册,不用登录,更不用魔法,点开就能用

完全免费的ChatGPT,最新整理,2023年8月24日,已人工验证, 不用注册,不用登录,更不用魔法,点开就能用! 第一个:网址地址统一放在文末啦!文末直达 看上图你就能…

基于ssm的共享客栈管理系统源码和论文

基于ssm的共享客栈管理系统源码和论文058 开发工具:idea 数据库mysql5.7 数据库链接工具:navcat,小海豚等 技术:ssm 摘 要 互联网发展至今,无论是其理论还是技术都已经成熟,而且它广泛参与在社会中的方方面面。…

ORB-SLAM2算法10之图像关键帧KeyFrame

文章目录 0 引言1 KeyFrame类1.1 构造函数1.2 成员函数1.3 关键帧之间共视图1.3.1 AddConnection1.3.2 UpdateBestCovisibles1.3.3 UpdateConnections1.3.4 EraseConnection1.3.5 SetBadFlag 1.4 地图点1.5 生成树 2 KeyFrame用途 0 引言 ORB-SLAM2算法7详细了解了System主类和…

机器学习实战之模型的解释性:Scikit-Learn的SHAP和LIME库详解

引言:机器学习模型的“黑箱”困境 机器学习模型的崛起让我们惊叹不已!不论是预测房价、识别图片中的猫狗,还是推荐给你喜欢的音乐,这些模型都表现得非常出色。但是,有没有想过,这些模型到底是如何做出这些决…

STM32 F103C8T6学习笔记13:IIC通信—AHT10温湿度传感器模块

今日学习一下这款AHT10 温湿度传感器模块,给我的OLED手环添加上测温湿度的功能。 文章提供源码、测试工程下载、测试效果图。 目录 AHT10温湿度传感器: 特性: 连接方式: 适用场所范围: 程序设计: 设…

大模型技术实践(二)|关于Llama 2你需要知道的那些事儿

在上期文章中,我们简要回顾了Llama模型的概况,本期文章我们将详细探讨【关于Llama 2】,你需要知道的那些事儿。 01-Llama 2的性能有多好? 作为Meta新发布的SOTA开源大型语言模型,Llama 2是Llama模型的延续和升级。Ll…

免费的png打包plist工具CppTextu,一款把若干资源图片拼接为一张大图的免费工具

经常做游戏打包贴图的都知道,要把图片打包为一张或多张大图,要使用打包工具TexturePacker。 TexturePacker官方版可以直接导入PSD、SWF、PNG、BMP等常见的图片格式,主要用于网页、游戏和动画的制作,它可以将多个小图片汇聚成一个…

java八股文面试[java基础]——CGLIB动态代理与JDK动态代理

CGLIB CGLIB简介: 什么是CGLIB CGLIB是一个强大的、高性能的代码生成库。其被广泛应用于AOP框架(Spring、dynaop)中,用以提供方法拦截操作。Hibernate作为一个比较受欢迎的ORM框架,同样使用CGLIB来代理单端&#xff…

iPhone 15预计在A16仿生芯片上运行,性能将有何提升?

苹果最新的移动芯片A17仿生芯片无疑让人兴奋不已,该芯片将成为今年一些iPhone 15机型的驱动力。A17基于3nm处理器,这是第一款提出这一主张的移动硅,由于其更紧凑的尺寸,它有望在性能和能效方面都有所提高。今年秋天买一部A17供电的…

【Java架构-包管理工具】-Maven私服搭建-Nexus(三)

本文摘要 Maven作为Java后端使用频率非常高的一款依赖管理工具,在此咱们由浅入深,分三篇文章(Maven基础、Maven进阶、私服搭建)来深入学习Maven,此篇为开篇主要介绍Maven私服搭建-Nexus 文章目录 本文摘要1. Nexus安装…

爬虫逆向实战(二十)--某99网站登录

一、数据接口分析 主页地址:某99网站 1、抓包 通过抓包可以发现登录接口是AC_userlogin 2、判断是否有加密参数 请求参数是否加密? 通过查看“载荷”可以发现txtPassword和aws是加密参数 请求头是否加密? 无响应是否加密? 无…

Win11本地安装Ubuntu 22.04 双系统简易教程

1.制作启动U盘 首先找到一个硬盘容量不小于4G的空U盘,需要对其进行格式化。 然后下载Ubuntu 22.04的iso文件到本地。 Ubuntu 22.04.1 LTS 中国地区下载链接 下载 UltraISO并制作启动U盘 UltraISO的下载地址 下载免费试用版 选择安装地址,无脑下一步…

Error running ‘FileApp‘: Command line is too long. Shorten command line for

报错如下 Error running FileApp: Command line is too long. Shorten command line for 解决方案如下: 打开运行配置 点击上面,默认是收起来的,点击下,下面选择标注的红色的, 重新运行,可以正常启动了

首发!2025年超500万辆规模,揭榜「融合泊车」TOP10玩家

作为行泊一体赛道关键的一环,融合泊车(基于全景环视超声波雷达)及后续的高阶泊车方案再次成为行业关注的焦点。 除了部分头部车企自研之外,第三方供应商的市场机会也在扩大。一方面,泊车厂商也在拓展行泊一体方案&…

ChatGPT⼊门到精通(1):ChatGPT 是什么

⼀、直观感受 1、公司 OpenAI(美国) 2、官⽅⽹站 3、登录ChatGPT ![在这里插入图片描述](https://img-blog.csdnimg.cn/26901096553a4ba0a5c88c49b2601e6a.png 填⼊帐号、密码,点击登录。登录成功,如下 3、和ChatGPT对话 开始…

专题-【稀疏矩阵的三元组存储】

三元组存储表示: 列序递增转置法:

计算机竞赛 基于YOLO实现的口罩佩戴检测 - python opemcv 深度学习

文章目录 0 前言1 课题介绍2 算法原理2.1 算法简介2.2 网络架构 3 关键代码4 数据集4.1 安装4.2 打开4.3 选择yolo标注格式4.4 打标签4.5 保存 5 训练6 实现效果6.1 pyqt实现简单GUI6.3 视频识别效果6.4 摄像头实时识别 7 最后 0 前言 🔥 优质竞赛项目系列&#xf…

CSS中如何实现元素之间的间距(Margin)合并效果?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 外边距合并的示例:⭐ 如何控制外边距合并:⭐ 写在最后 ⭐ 专栏简介 前端入门之旅:探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅&#xff…

sizeof和strlen的对比

文章目录 🚩前言🚩sizeof🚩strlen🚩sizeof和strlen对比 🚩前言 很多小白在学习中,经常将sizeof和strlen弄混了。本篇文章,小编讲解一下sizeof和strlen的区别。🤷‍♂️ &#x1f6a9…

windows查看/删除DNS缓存

一、查看DNS缓存 打开CMD,输入ipconfig/displaydns 二、删除DNS缓存 打开CMD,输入ipconfig/flushdns