前言

在我们日常开发中,我们可能很随意把数据库密码直接明文暴露在配置文件中,在开发环境可以这么做,但是在生产环境,是相当不建议这么做,毕竟安全无小事,谁也不知道哪天密码就莫名其妙泄露了。今天就来聊聊在springboot项目中如何对数据库密码进行加密

正文

方案一、使用druid数据库连接池对数据库密码加密

1、pom.xml引入druid包

为了方便其他的操作,这边直接引入druid的starter

<dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>${druid.version}</version></dependency>

2、利用com.alibaba.druid.filter.config.ConfigTools生成公私钥

ps: 生成的方式有两种,一种利用命令行生成,一种直接写个工具类生成。本文示例直接采用工具类生成

工具类代码如下

/*** alibaba druid加解密规则:* 明文密码+私钥(privateKey)加密=加密密码* 加密密码+公钥(publicKey)解密=明文密码*/
public final class DruidEncryptorUtils {private static String privateKey;private static String publicKey;static {try {String[] keyPair = ConfigTools.genKeyPair(512);privateKey = keyPair[0];System.out.println(String.format("privateKey-->%s",privateKey));publicKey = keyPair[1];System.out.println(String.format("publicKey-->%s",publicKey));} catch (NoSuchAlgorithmException e) {e.printStackTrace();} catch (NoSuchProviderException e) {e.printStackTrace();}}/*** 明文加密* @param plaintext* @return*/@SneakyThrowspublic static String encode(String plaintext){System.out.println("明文字符串:" + plaintext);String ciphertext = ConfigTools.encrypt(privateKey,plaintext);System.out.println("加密后字符串:" + ciphertext);return ciphertext;}/*** 解密* @param ciphertext* @return*/@SneakyThrowspublic static String decode(String ciphertext){System.out.println("加密字符串:" + ciphertext);String plaintext = ConfigTools.decrypt(publicKey,ciphertext);System.out.println("解密后的字符串:" + plaintext);return plaintext;}

3、修改数据库的配置文件内容信息

a 、 修改密码

把密码替换成用DruidEncryptorUtils这个工具类生成的密码

 password: ${DATASOURCE_PWD:HB5FmUeAI1U81YJrT/T6awImFg1/Az5o8imy765WkVJouOubC2H80jqmZrr8L9zWKuzS/8aGzuQ4YySAkhywnA==}

b、 filter开启config

 filter:config:enabled: true

c、配置connectionProperties属性

 connection-properties: config.decrypt=true;config.decrypt.key=${spring.datasource.publickey}

ps: spring.datasource.publickey为工具类生成的公钥

附录: 完整数据库配置

spring:datasource:type: com.alibaba.druid.pool.DruidDataSourcedriverClassName: com.mysql.cj.jdbc.Driverurl: ${DATASOURCE_URL:jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai}username: ${DATASOURCE_USERNAME:root}password: ${DATASOURCE_PWD:HB5FmUeAI1U81YJrT/T6awImFg1/Az5o8imy765WkVJouOubC2H80jqmZrr8L9zWKuzS/8aGzuQ4YySAkhywnA==}publickey: MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAIvP9xF4RCM4oFiu47NZY15iqNOAB9K2Ml9fiTLa05CWaXK7uFwBImR7xltZM1frl6ahWAXJB6a/FSjtJkTZUJECAwEAAQ==druid:# 初始连接数initialSize: 5# 最小连接池数量minIdle: 10# 最大连接池数量maxActive: 20# 配置获取连接等待超时的时间maxWait: 60000# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒timeBetweenEvictionRunsMillis: 60000# 配置一个连接在池中最小生存的时间,单位是毫秒minEvictableIdleTimeMillis: 300000# 配置一个连接在池中最大生存的时间,单位是毫秒maxEvictableIdleTimeMillis: 900000# 配置检测连接是否有效validationQuery: SELECT 1 FROM DUALtestWhileIdle: truetestOnBorrow: falsetestOnReturn: falsewebStatFilter:enabled: truestatViewServlet:enabled: true# 设置白名单,不填则允许所有访问allow:url-pattern: /druid/*# 控制台管理用户名和密码login-username:login-password:filter:stat:enabled: true# 慢SQL记录log-slow-sql: trueslow-sql-millis: 1000merge-sql: truewall:config:multi-statement-allow: trueconfig:enabled: trueconnection-properties: config.decrypt=true;config.decrypt.key=${spring.datasource.publickey}

方案二:使用jasypt对数据库密码加密

1、pom.xml引入jasypt包

<dependency><groupId>com.github.ulisesbocchio</groupId><artifactId>jasypt-spring-boot-starter</artifactId><version>${jasypt.verison}</version></dependency>

2、利用jasypt提供的工具类对明文密码进行加密

加密工具类如下

public final class JasyptEncryptorUtils {private static final String salt = "lybgeek";private static BasicTextEncryptor basicTextEncryptor = new BasicTextEncryptor();static {basicTextEncryptor.setPassword(salt);}private JasyptEncryptorUtils(){}/*** 明文加密* @param plaintext* @return*/public static String encode(String plaintext){System.out.println("明文字符串:" + plaintext);String ciphertext = basicTextEncryptor.encrypt(plaintext);System.out.println("加密后字符串:" + ciphertext);return ciphertext;}/*** 解密* @param ciphertext* @return*/public static String decode(String ciphertext){System.out.println("加密字符串:" + ciphertext);ciphertext = "ENC(" + ciphertext + ")";if (PropertyValueEncryptionUtils.isEncryptedValue(ciphertext)){String plaintext = PropertyValueEncryptionUtils.decrypt(ciphertext,basicTextEncryptor);System.out.println("解密后的字符串:" + plaintext);return plaintext;}System.out.println("解密失败");return "";}
}

3、修改数据库的配置文件内容信息

a、 用ENC包裹用JasyptEncryptorUtils 生成的加密串

password: ${DATASOURCE_PWD:ENC(P8m43qmzqN4c07DCTPey4Q==)}

b、 配置密钥和指定加解密算法

jasypt:encryptor:password: lybgeekalgorithm: PBEWithMD5AndDESiv-generator-classname: org.jasypt.iv.NoIvGenerator

因为我工具类使用的是加解密的工具类是BasicTextEncryptor,其对应配置加解密就是PBEWithMD5AndDES和org.jasypt.iv.NoIvGenerator

ps: 在生产环境中,建议使用如下方式配置密钥,避免密钥泄露

java -jar -Djasypt.encryptor.password=lybgeek

附录: 完整数据库配置

spring:datasource:type: com.alibaba.druid.pool.DruidDataSourcedriverClassName: com.mysql.cj.jdbc.Driverurl: ${DATASOURCE_URL:ENC(kT/gwazwzaFNEp7OCbsgCQN7PHRohaTKJNdGVgLsW2cH67zqBVEq7mN0BTIXAeF4/Fvv4l7myLFx0y6ap4umod7C2VWgyRU5UQtKmdwzQN3hxVxktIkrFPn9DM6+YahM0xP+ppO9HaWqA2ral0ejBCvmor3WScJNHCAhI9kHjYc=)}username: ${DATASOURCE_USERNAME:ENC(rEQLlqM5nphqnsuPj3MlJw==)}password: ${DATASOURCE_PWD:ENC(P8m43qmzqN4c07DCTPey4Q==)}druid:# 初始连接数initialSize: 5# 最小连接池数量minIdle: 10# 最大连接池数量maxActive: 20# 配置获取连接等待超时的时间maxWait: 60000# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒timeBetweenEvictionRunsMillis: 60000# 配置一个连接在池中最小生存的时间,单位是毫秒minEvictableIdleTimeMillis: 300000# 配置一个连接在池中最大生存的时间,单位是毫秒maxEvictableIdleTimeMillis: 900000# 配置检测连接是否有效validationQuery: SELECT 1 FROM DUALtestWhileIdle: truetestOnBorrow: falsetestOnReturn: falsewebStatFilter:enabled: truestatViewServlet:enabled: true# 设置白名单,不填则允许所有访问allow:url-pattern: /druid/*# 控制台管理用户名和密码login-username:login-password:filter:stat:enabled: true# 慢SQL记录log-slow-sql: trueslow-sql-millis: 1000merge-sql: truewall:config:multi-statement-allow: true
jasypt:encryptor:password: lybgeekalgorithm: PBEWithMD5AndDESiv-generator-classname: org.jasypt.iv.NoIvGenerator

方案三:自定义实现

实现原理: 利用spring后置处理器修改DataSource

1、自定义加解密工具类

/*** 利用hutool封装的加解密工具,以AES对称加密算法为例*/
public final class EncryptorUtils {private static String secretKey;static {secretKey = Hex.encodeHexString(SecureUtil.generateKey(SymmetricAlgorithm.AES.getValue()).getEncoded());System.out.println("secretKey-->" + secretKey);System.out.println("--------------------------------------------------------------------------------------");}/*** 明文加密* @param plaintext* @return*/@SneakyThrowspublic static String encode(String plaintext){System.out.println("明文字符串:" + plaintext);byte[] key = Hex.decodeHex(secretKey.toCharArray());String ciphertext =  SecureUtil.aes(key).encryptHex(plaintext);System.out.println("加密后字符串:" + ciphertext);return ciphertext;}/*** 解密* @param ciphertext* @return*/@SneakyThrowspublic static String decode(String ciphertext){System.out.println("加密字符串:" + ciphertext);byte[] key = Hex.decodeHex(secretKey.toCharArray());String plaintext = SecureUtil.aes(key).decryptStr(ciphertext);System.out.println("解密后的字符串:" + plaintext);return plaintext;}/*** 明文加密* @param plaintext* @return*/@SneakyThrowspublic static String encode(String secretKey,String plaintext){System.out.println("明文字符串:" + plaintext);byte[] key = Hex.decodeHex(secretKey.toCharArray());String ciphertext =  SecureUtil.aes(key).encryptHex(plaintext);System.out.println("加密后字符串:" + ciphertext);return ciphertext;}/*** 解密* @param ciphertext* @return*/@SneakyThrowspublic static String decode(String secretKey,String ciphertext){System.out.println("加密字符串:" + ciphertext);byte[] key = Hex.decodeHex(secretKey.toCharArray());String plaintext = SecureUtil.aes(key).decryptStr(ciphertext);System.out.println("解密后的字符串:" + plaintext);return plaintext;}}

2、编写后置处理器

public class DruidDataSourceEncyptBeanPostProcessor implements BeanPostProcessor {private CustomEncryptProperties customEncryptProperties;private DataSourceProperties dataSourceProperties;public DruidDataSourceEncyptBeanPostProcessor(CustomEncryptProperties customEncryptProperties, DataSourceProperties dataSourceProperties) {this.customEncryptProperties = customEncryptProperties;this.dataSourceProperties = dataSourceProperties;}@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {if(bean instanceof DruidDataSource){if(customEncryptProperties.isEnabled()){DruidDataSource druidDataSource = (DruidDataSource)bean;System.out.println("--------------------------------------------------------------------------------------");String username = dataSourceProperties.getUsername();druidDataSource.setUsername(EncryptorUtils.decode(customEncryptProperties.getSecretKey(),username));System.out.println("--------------------------------------------------------------------------------------");String password = dataSourceProperties.getPassword();druidDataSource.setPassword(EncryptorUtils.decode(customEncryptProperties.getSecretKey(),password));System.out.println("--------------------------------------------------------------------------------------");String url = dataSourceProperties.getUrl();druidDataSource.setUrl(EncryptorUtils.decode(customEncryptProperties.getSecretKey(),url));System.out.println("--------------------------------------------------------------------------------------");}}return bean;}
}

3、修改数据库的配置文件内容信息

a 、 修改密码

把密码替换成用自定义加密工具类生成的加密密码

  password: ${DATASOURCE_PWD:fb31cdd78a5fa2c43f530b849f1135e7}

b 、 指定密钥和开启加密功能

custom:encrypt:enabled: truesecret-key: 2f8ba810011e0973728afa3f28a0ecb6

ps: 同理secret-key最好也不要直接暴露在配置文件中,可以用-Dcustom.encrypt.secret-key指定

附录: 完整数据库配置

spring:datasource:type: com.alibaba.druid.pool.DruidDataSourcedriverClassName: com.mysql.cj.jdbc.Driverurl: ${DATASOURCE_URL:dcb268cf3a2626381d2bc5c96f94fb3d7f99352e0e392362cb818a321b0ca61f3a8dad3aeb084242b745c61a1d3dc244ed1484bf745c858c44560dde10e60e90ac65f77ce2926676df7af6b35aefd2bb984ff9a868f1f9052ee9cae5572fa015b66a602f32df39fb1bbc36e04cc0f148e4d610a3e5d54f2eb7c57e4729c9d7b4}username: ${DATASOURCE_USERNAME:61db3bf3c6d3fe3ce87549c1af1e9061}password: ${DATASOURCE_PWD:fb31cdd78a5fa2c43f530b849f1135e7}druid:# 初始连接数initialSize: 5# 最小连接池数量minIdle: 10# 最大连接池数量maxActive: 20# 配置获取连接等待超时的时间maxWait: 60000# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒timeBetweenEvictionRunsMillis: 60000# 配置一个连接在池中最小生存的时间,单位是毫秒minEvictableIdleTimeMillis: 300000# 配置一个连接在池中最大生存的时间,单位是毫秒maxEvictableIdleTimeMillis: 900000# 配置检测连接是否有效validationQuery: SELECT 1 FROM DUALtestWhileIdle: truetestOnBorrow: falsetestOnReturn: falsewebStatFilter:enabled: truestatViewServlet:enabled: true# 设置白名单,不填则允许所有访问allow:url-pattern: /druid/*# 控制台管理用户名和密码login-username:login-password:filter:stat:enabled: true# 慢SQL记录log-slow-sql: trueslow-sql-millis: 1000merge-sql: truewall:config:multi-statement-allow: true
custom:encrypt:enabled: truesecret-key: 2f8ba810011e0973728afa3f28a0ecb6

总结

上面三种方案,个人比较推荐用jasypt这种方案,因为它不仅可以对密码加密,也可以对其他内容加密。而druid只能对数据库密码加密。至于自定义的方案,属于练手,毕竟开源已经有的东西,就不要再自己造轮子了。

最后还有一个注意点就是jasypt如果是高于2版本,且以低于3.0.3,会导致配置中心,比如apollo或者nacos的动态刷新配置失效(最新版的3.0.3官方说已经修复了这个问题)。

如果有使用配置中心的话,jasypt推荐使用3版本以下,或者使用3.0.3版本

demo链接

https://github.com/lyb-geek/springboot-learning/tree/master/springboot-datasouce-encrypt

聊聊springboot项目数据库密码如何加密相关推荐

  1. pkcs1解密 springboot_使用springboot完成密码的加密解密

    现今对于大多数公司来说,信息安全工作尤为重要,就像京东,阿里巴巴这样的大公司来说,信息安全是最为重要的一个话题,举个简单的例子: 就像这样的密码公开化,很容易造成一定的信息的泄露.所以今天我们要讲的就 ...

  2. Springboot之Jasypt配置文件加密/解密

    Jasypt配置文件加密/机密 一.Jasypt介绍 二.Springboot整合Jasypt 2.1 环境配置 2.2 添加依赖 2.3 添加Jasypt配置 2.4 编写加/解密工具类 2.5 修 ...

  3. db 文件 加密_有人说Kettle 数据库JNDI方式数据库密码不能加密,搞他!

    Kettle 数据库JNDI方式数据库密码不能加密,搞他! 1新建数据库连接 1.1 普通局部变量 Step 1: 选择连接类型,这里选择Oracle Step 2: 连接方式选择Native(JDB ...

  4. 将 Shiro 作为应用的权限基础 五:密码的加密/解密在Spring中的应用

    2019独角兽企业重金招聘Python工程师标准>>> 考虑系统密码的安全,目前大多数系统都不会把密码以明文的形式存放到数据库中. 一把会采取以下几种方式对密码进行处理 密码的存储 ...

  5. java对密码进行加密的方法_如何在JAVA中使用MD5加密对密码进行加密

    如何在JAVA中使用MD5加密对密码进行加密 发布时间:2020-11-25 17:12:40 来源:亿速云 阅读:118 作者:Leah 本篇文章为大家展示了如何在JAVA中使用MD5加密对密码进行 ...

  6. Android 使用MD5对SharedPreferences密码进行加密

    在每个Android软件都会使用到SharedPreferences,将密码保存在本地,但是由于没有对密码进行加密,只要用户对手机进行root,获取了权限就很容易得到密码,为了防止密码外露,每个And ...

  7. 如何保证用户登陆时提交密码已经加密

    如何保证用户登陆时提交密码已经加密?密码是否已加密,需要客户端和服务端建立约定,双方按约定办事就行了. 这里提到的另一个问题是,如何保证传输安全? 最理想的方案当然是走 HTTPS 协议. HTTPS ...

  8. 使用selenium进行密码破解(绕过账号密码JS加密)

    经常碰到网站,账号密码通过js加密后进行提交.通过burp拦截抓到的账号密码是加密后的,所以无法通过burp instruder进行破解.只能模拟浏览器填写表单并点击登录按钮进行破解.于是想到了自动化 ...

  9. was控制台的用户和密码怎样加密使用_Python爬虫进阶 | X咕视频密码与指纹加密分析...

    先来看看今天的受害者: aHR0cDovL3d3dy5taWd1dmlkZW8uY29tL21ncy93ZWJzaXRlL3ByZC9pbmRleC5odG1s 一.分析密码加密 这次分析的是他登陆的 ...

最新文章

  1. 理财工具——七大标准比率
  2. 【数字信号处理】傅里叶变换性质 ( 序列傅里叶变换共轭对称性质示例 | 证明 原序列实部 x_R(n) 的 傅里叶变换 是 原序列傅里叶变换 的 共轭对称序列 )
  3. php Xdebug的安装与使用详解
  4. linux 几个文件夹作用,linux下每一个文件夹的作用.docx
  5. 用开源代码如何建立网站_建立开源社区时要考虑的6件事
  6. 如何在Spyder中使用远程服务器的python来调试代码
  7. 机器视觉:USB 3.0知识答疑
  8. SharedMaterial的一些问题
  9. 使用python将视频中的音频分离出来
  10. 手机wps取消不等宽分栏_wps取消分栏怎么设置
  11. Android小程序-涂鸦板
  12. jquery返回上一页,前一页
  13. 图片压缩-陈浩然,卧薪尝胆70天内推入职阿里
  14. 程序设计思维月模拟题2-CSP201609-3 炉石传说
  15. 视频转mp3格式怎么弄?
  16. 解决ReactNative崩溃:Can't find variable: __fbBatchedBridge
  17. 二十三、动网格Smoothing Diffusion方法及实例
  18. vsftp客户端_Vsftp使用
  19. 关于onreadystatechange属性的一点疑问
  20. 飞翔的小鸟java_java 飞翔的小鸟 小游戏源码

热门文章

  1. labelme标注理解
  2. js向上取整 向下取整四舍五入方法总结
  3. Cardboard XR Plugin For Unity
  4. 练习题007:求两个数的最大公因数和最小公倍数
  5. Android ADB资源被占用,连接不上?部分手机连接不上
  6. scala 系列 ---- take,takeRight,takeWhile的使用详解用法及代码示例
  7. django mysql数据同步_[django自动同步数据库]Django数据库同步操作技巧详解
  8. python中print格式化输出%g_python怎么格式化输出
  9. 802.3帧前导码小结
  10. NSFC: 研究内容可选的结构