前言

在我们日常开发中,我们可能很随意把数据库密码直接明文暴露在配置文件中,在开发环境可以这么做,但是在生产环境,是相当不建议这么做,毕竟安全无小事,谁也不知道哪天密码就莫名其妙泄露了。今天就来聊聊在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. Linux整合Apache和SVN
  2. python学习详解_深入解析Python小白学习【操作列表】
  3. 深入解析 Dubbo 3.0 服务端暴露全流程
  4. 登录及注册模块设置与流程图
  5. android怎么垂直居中且靠右,placeholder 靠右垂直居中/位置兼容
  6. c语言定时器回调函数的参数,定时器的简单实现即回调函数的运用
  7. flask ajax 笔记
  8. 29 MM配置-采购-采购申请-采购申请审批策略-编辑特性
  9. VIM使用小技巧-重新载入文件
  10. Java Jackson
  11. 拓端tecdat|R语言高维数据惩罚回归方法:主成分回归PCR、岭回归、lasso、弹性网络elastic net分析基因数据
  12. CART树算法的剪枝算法
  13. TOGAF9企业架构规划与设计学习考试经验简记
  14. 计算机函数两个表格找相同,wps筛选出两个表格中的重复项(countif 函数简单使用)【已解决】...
  15. 638-字符串模式匹配-KMP算法
  16. 15分钟的html倒计时,js实现5分钟倒计时
  17. MongoDB中balancer操作
  18. 腾讯云主机SSH连接不上如何解决
  19. Visual C++游戏编程基础之多背景循环动画
  20. 聊一聊28岁程序员被裁,我的思考和建议

热门文章

  1. labelme的使用方式
  2. 使用代理重加密+PlatONE,来保证数据可信、安全地共享
  3. 论文学习——基于查询的workload预测(CMU)
  4. 我的创作纪念日一周年
  5. 在云服务器上部署web项目(CVM)
  6. 敏捷开发和Scrum、Kanban、XP的关系与区别
  7. CISP-PTE web渗透通关攻略
  8. 基尼系数 java_决策树的基尼系数计算过程
  9. 5w每秒的高并发优化:电商秒杀与抢购
  10. log4j logger,Threshold,additivity细节注意