大家好,我是冰河~~

最近,有位读者私信我说,他们公司的项目中配置的数据库密码没有加密,编译打包后的项目被人反编译了,从项目中成功获取到数据库的账号和密码,进一步登录数据库获取了相关的数据,并对数据库进行了破坏。虽然这次事故影响的范围不大,但是这足以说明很多公司对于项目的安全性问题重视程度不够。

如果文章对你有点帮助,小伙伴们点赞,收藏,评论,分享,走起呀~~

数据泄露缘由

由于Java项目的特殊性,打包后的项目如果没有做代码混淆,配置文件中的重要配置信息没有做加密处理的话,一旦打包的程序被反编译后,很容易获得这些敏感信息,进一步对项目或者系统造成一定的损害。所以,无论是公司层面还是开发者个人,都需要对项目的安全性有所重视。

今天,我们就一起来聊聊如何在项目中加密数据库密码,尽量保证数据库密码的安全性。本文中,我使用的数据库连接池是阿里开源的Druid。

数据库密码加密

配置数据库连接池

这里,我就简单的使用xml配置进行演示,当然小伙伴们也可以使用Spring注解方式,或者使用SpringBoot进行配置。

<!--数据源加密操作-->
<bean id="dbPasswordCallback" class="com.binghe.dbsource.DBPasswordCallback" lazy-init="true"/><bean id="statFilter" class="com.alibaba.druid.filter.stat.StatFilter" lazy-init="true"><property name="logSlowSql" value="true"/><property name="mergeSql" value="true"/></bean>
<!-- 数据库连接 -->
<bean id="readDataSource" class="com.alibaba.druid.pool.DruidDataSource"destroy-method="close" init-method="init" lazy-init="true"><property name="driverClassName" value="${driver}"/><property name="url" value="${url1}"/><property name="username" value="${username}"/><property name="password" value="${password}"/><!-- 初始化连接大小 --><property name="initialSize" value="${initialSize}"/><!-- 连接池最大数量 --><property name="maxActive" value="${maxActive}"/><!-- 连接池最小空闲 --><property name="minIdle" value="${minIdle}"/><!-- 获取连接最大等待时间 --><property name="maxWait" value="${maxWait}"/><!-- --><property name="defaultReadOnly" value="true"/><property name="proxyFilters"><list><ref bean="statFilter"/></list></property><property name="filters" value="${druid.filters}"/><property name="connectionProperties" value="password=${password}"/><property name="passwordCallback" ref="dbPasswordCallback"/><property name="testWhileIdle" value="true"/><property name="testOnBorrow" value="false"/><property name="testOnReturn" value="false"/><property name="validationQuery" value="SELECT 'x'"/><property name="timeBetweenLogStatsMillis" value="60000"/><!-- 配置一个连接在池中最小生存的时间,单位是毫秒 --><property name="minEvictableIdleTimeMillis" value="${minEvictableIdleTimeMillis}"/><!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 --><property name="timeBetweenEvictionRunsMillis" value="${timeBetweenEvictionRunsMillis}"/>
</bean>

其中要注意的是:我在配置文件中进行了如下配置。

<bean id="dbPasswordCallback" class="com.binghe.dbsource.DBPasswordCallback" lazy-init="true"/><property name="connectionProperties" value="password=${password}"/>
<property name="passwordCallback" ref="dbPasswordCallback"/>

生成RSA密钥

使用RSA公钥和私钥,生成一对公钥和私钥的工具类如下所示。

package com.binghe.crypto.rsa;
import java.security.Key;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.HashMap;
import java.util.Map;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
/*** 算法工具类* @author binghe*/
public class RSAKeysUtil {public static final String KEY_ALGORITHM = "RSA";public static final String SIGNATURE_ALGORITHM = "MD5withRSA";private static final String PUBLIC_KEY = "RSAPublicKey";private static final String PRIVATE_KEY = "RSAPrivateKey";public static void main(String[] args) {Map<String, Object> keyMap;try {keyMap = initKey();String publicKey = getPublicKey(keyMap);System.out.println(publicKey);String privateKey = getPrivateKey(keyMap);System.out.println(privateKey);} catch (Exception e) {e.printStackTrace();}}public static String getPublicKey(Map<String, Object> keyMap) throws Exception {Key key = (Key) keyMap.get(PUBLIC_KEY);byte[] publicKey = key.getEncoded();return encryptBASE64(key.getEncoded());}public static String getPrivateKey(Map<String, Object> keyMap) throws Exception {Key key = (Key) keyMap.get(PRIVATE_KEY);byte[] privateKey = key.getEncoded();return encryptBASE64(key.getEncoded());}public static byte[] decryptBASE64(String key) throws Exception {return (new BASE64Decoder()).decodeBuffer(key);}public static String encryptBASE64(byte[] key) throws Exception {return (new BASE64Encoder()).encodeBuffer(key);}public static Map<String, Object> initKey() throws Exception {KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM);keyPairGen.initialize(1024);KeyPair keyPair = keyPairGen.generateKeyPair();RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();Map<String, Object> keyMap = new HashMap<String, Object>(2);keyMap.put(PUBLIC_KEY, publicKey);keyMap.put(PRIVATE_KEY, privateKey);return keyMap;}
}

运行这个类,输出的结果如下:

在输出的结果信息中,上边是公钥下边是私钥。

对密码进行加密

使用私钥对明文密码进行加密,示例代码如下所示。

package com.binghe.dbsource.demo;
import com.alibaba.druid.filter.config.ConfigTools;
/*** 使用密钥加密数据库密码的代码示例* @author binghe*/
public class ConfigToolsDemo {/*** 私钥对数据进行加密*/private static final String PRIVATE_KEY_STRING = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKtq3IJP5idDXZjML6I8HTAl0htWZSOO43LhZ/+stsIG50WsuW0UJ2vdrEtjvTEfJxP6N1VNrbsF9Lrsp6A4AyUwx00ZUueTlbUaX60134Di0IdQ3C4RTt5mPIbF3hUKers8csltgYR4fByvR3Eq4lt+jAolVHKmyzufukH3d3vJAgMBAAECgYBXiyW+r4t9NdxRMsaI9mZ5tncNWxwgAtOKUi/I1a4ofVoTrVitqoNPhVB+2BtBQQW2IC2uNROq1incZQxeuPxxZJgz1lnnZyHvDE3wuMZAGTcalID+5xBZ2j6fBtDnxbfIL/tIfGJrX+0mUXP2LIo242yQIlzr7RV60iuE2Ms54QJBAOqE0ycvztfxubqBWO7l8PsS3qDUv9lLBBO/Q8I+qVl4tzh+SD/13BqLuaj9eWPGPyml+faWtbmuQgBqauT23l0CQQC7HmMC0CgZS6taQxmPkXzw0XhxZ7tBZeLWl87hqc2S79P0BPX9kPukiC4LpA5xyz0CZ5azJXd2EwRsxF32GERdAkASEi4bJOnxZeUD5BewQPOyxR92kS4/VjJ4OxLDkwSFqnGj3sc+dnmBaibiSLXj5FDVqr56K97Q8gaP9aNLBWLZAkEAjwGnPBQoQUTinaZgl6fibA47VbiolU+v8L+u3iqvMVhXjcxo0DUJDXMCdeUZIQDqDLdsplfBGB1qqVHeWeGsBQJAXGNe2I510WLjMdn+olhi5ZjMr4F4oiF8TAE1Uu74FWn0sc418E7ScgXPCgpGVK0QaXo2wtDeMIoxJwm9Zh8oyg==";public static void main(String[] args) throws Exception {//密码明文,也就是数据库的密码String plainText = "root";System.out.printf(ConfigTools.encrypt(PRIVATE_KEY_STRING, plainText));}
}

运行上述代码示例,结果如下所示。

然后将数据库配置的链接密码改为这个输出结果如下:

jdbc.username=root
jdbc.password=EA9kJ8NMV8zcb5AeLKzAsL/8F1ructRjrqs69zM70BwDyeMtxuEDEVe9CBeRgZ+qEUAshhWGEDk9ay3TLLKrf2AOE3VBn+w8+EfUIEXFy8u3jYViHeV8yc8Z7rghdFShhd/IJbjqbsro1YtB9pHrl4EpbCqp7RM2rZR/wJ0WN48=

编写解析数据库密码的类

package com.binghe.dbsource;
import java.util.Properties;
import com.alibaba.druid.filter.config.ConfigTools;
import com.alibaba.druid.util.DruidPasswordCallback;
/*** 数据库密码回调* @author binghe*/
public class DBPasswordCallback extends DruidPasswordCallback {private static final long serialVersionUID = -4601105662788634420L;/*** password的属性*/private static final String DB_PWD = "password";/*** 数据对应的公钥*/public static final String PUBLIC_KEY_STRING = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCratyCT+YnQ12YzC+iPB0wJdIbVmUjjuNy4Wf/rLbCBudFrLltFCdr3axLY70xHycT+jdVTa27BfS67KegOAMlMMdNGVLnk5W1Gl+tNd+A4tCHUNwuEU7eZjyGxd4VCnq7PHLJbYGEeHwcr0dxKuJbfowKJVRypss7n7pB93d7yQIDAQAB";@Overridepublic void setProperties(Properties properties) {super.setProperties(properties);String pwd = properties.getProperty(DB_PWD);if (pwd != null && !"".equals(pwd.trim())) {try {//这里的password是将jdbc.properties配置得到的密码进行解密之后的值//所以这里的代码是将密码进行解密//TODO 将pwd进行解密;String password = ConfigTools.decrypt(PUBLIC_KEY_STRING, pwd); setPassword(password.toCharArray());} catch (Exception e) {setPassword(pwd.toCharArray());}}}
}

这里DBPasswordCallback类,就是在配置文件中配置的DBPasswordCallback类,如下所示。

<bean id="dbPasswordCallback" class="com.binghe.dbsource.DBPasswordCallback" lazy-init="true"/>

其中PasswordCallback是javax.security.auth.callback包下面的,底层安全服务实例化一个 PasswordCallback 并将其传递给 CallbackHandler 的 handle 方法,以获取密码信息。

当然,除了使用上述的方式,自己也可以对应一套加解密方法,只需要将 DBPasswordCallback的 String password = ConfigTools.decrypt(PUBLIC_KEY_STRING, pwd); 替换即可。

另外,在编写解析数据库密码的类时,除了可以继承阿里巴巴开源的Druid框架中的DruidPasswordCallback类外,还可以直接继承自Spring提供的PropertyPlaceholderConfigurer类,如下所示。

public class DecryptPropertyPlaceholderConfigurer extends PropertyPlaceholderConfigurer{/*** 重写父类方法,解密指定属性名对应的属性值*/@Overrideprotected String convertProperty(String propertyName,String propertyValue){if(isEncryptPropertyVal(propertyName)){return DesUtils.getDecryptString(propertyValue);//调用解密方法}else{return propertyValue;}}/*** 判断属性值是否需要解密,这里我约定需要解密的属性名用encrypt开头*/private boolean isEncryptPropertyVal(String propertyName){if(propertyName.startsWith("encrypt")){return true;}else{return false;}}
}

此时,就需要将xml文件中的如下配置

<bean id="dbPasswordCallback" class="com.binghe.dbsource.DBPasswordCallback" lazy-init="true"/>

修改为下面的配置。

<bean id="dbPasswordCallback" class="com.binghe.dbsource.DecryptPropertyPlaceholderConfigurer" lazy-init="true"/>

到此,在项目中对数据库密码进行加密和解析的整个过程就完成了。

写在最后

如果你想进大厂,想升职加薪,或者对自己现有的工作比较迷茫,都可以私信我交流,希望我的一些经历能够帮助到大家~~

推荐阅读:

  • 《从零到上亿用户,我是如何一步步优化MySQL数据库的?(建议收藏)》
  • 《我用多线程进一步优化了亿级流量电商业务下的海量数据校对系统,性能再次提升了200%!!(全程干货,建议收藏)》
  • 《我用多线程优化了亿级流量电商业务下的海量数据校对系统,性能直接提升了200%!!(全程干货,建议收藏)》
  • 《我用10张图总结出了这份并发编程最佳学习路线!!(建议收藏)》
  • 《高并发场景下一种比读写锁更快的锁,看完我彻底折服了!!(建议收藏)》
  • 《全网最全性能优化总结!!(冰河吐血整理,建议收藏)》
  • 《三天撸完了MyBatis,各位随便问!!(冰河吐血整理,建议收藏)》
  • 《奉劝那些刚参加工作的学弟学妹们:要想进大厂,这些并发编程知识是你必须要掌握的!完整学习路线!!(建议收藏)》
  • 《奉劝那些刚参加工作的学弟学妹们:要想进大厂,这些核心技能是你必须要掌握的!完整学习路线!!(建议收藏)》
  • 《奉劝那些刚参加工作的学弟学妹们:这些计算机与操作系统基础知识越早知道越好!万字长文太顶了!!(建议收藏)》
  • 《我用三天时间开发了一款老少皆宜的国民级游戏,支持播放音乐,现开放完整源代码和注释(建议收藏)!!》
  • 《我是全网最硬核的高并发编程作者,CSDN最值得关注的博主,大家同意吗?(建议收藏)》
  • 《毕业五年,从月薪3000到年薪百万,我掌握了哪些核心技能?(建议收藏)》
  • 《我入侵了隔壁妹子的Wifi,发现。。。(全程实战干货,建议收藏)》
  • 《千万不要轻易尝试“熊猫烧香”,这不,我后悔了!》
  • 《清明节偷偷训练“熊猫烧香”,结果我的电脑为熊猫“献身了”!》
  • 《7.3万字肝爆Java8新特性,我不信你能看完!(建议收藏)》
  • 《在业务高峰期拔掉服务器电源是一种怎样的体验?》
  • 《全网最全Linux命令总结!!(史上最全,建议收藏)》
  • 《用Python写了个工具,完美破解了MySQL!!(建议收藏)》
  • 《SimpleDateFormat类到底为啥不是线程安全的?(附六种解决方案,建议收藏)》
  • 《MySQL 8中新增的这三大索引,直接让MySQL起飞了,你竟然还不知道!!(建议收藏)》
  • 《撸完Spring源码,我开源了这个分布式缓存框架!!(建议收藏)》
  • 《亿级流量高并发秒杀系统商品“超卖”了,只因使用的JDK同步容器中存在这两个巨大的坑!!(踩坑实录,建议收藏)》
  • 《奉劝那些刚参加工作的学弟学妹们:要想学好并发编程,这些并发容器的坑是你必须要注意的!!(建议收藏)》

好了,今天就到这儿吧,小伙伴们点赞、收藏、评论,一键三连走起呀,我是冰河,我们下期见~~

项目配置不当引发了数据泄露,人已裂开!!(建议收藏)相关推荐

  1. 项目配置不当引发了数据泄露,人已裂开!!

    最近,有位读者私信我说,他们公司的项目中配置的数据库密码没有加密,编译打包后的项目被人反编译了,从项目中成功获取到数据库的账号和密码,进一步登录数据库获取了相关的数据,并对数据库进行了破坏. 虽然这次 ...

  2. Kramdown 配置不当引发 GitHub Pages 多个 RCE,得 $2.5万($6.1万系列之二)

     聚焦源代码安全,网罗国内外最新资讯! 编译:奇安信代码卫士团队 我一直都在盯着 GitHub 企业版会何时修复之前报的漏洞.结果发现GitHub 还修复了 Kramdown 中的一个严重漏洞. 该漏 ...

  3. php 扩展 suhosin 配置不当引发的报错及其解决方法

    1. /var/log/messages 频繁报错: Jul 24 03:27:04 localhost suhosin[9115]: ALERT - script tried to increase ...

  4. 热乎乎的蚂蚁金服面经分享,offer已到手建议收藏(Java岗、附答案解析)

    1.幸运而匆忙的一面 一面完等了差不多半个月才突然接到二面面试官的电话. 一面可能是简历面,所以问题比较简单. ArrayList和LinkedList区别? ArrayList 是一个可改变大小的数 ...

  5. 实训项目四 powerpoint 综合应用_抗震支吊架在机电安装项目上的综合应用,陕暖协建议收藏...

    本文源自网络 引言根据国家标准<建筑抗震设计规范>GB50011-2010 中第13.4.3 条和<建筑机电工程抗震设计规范>GB50981-2014中第3.1.3条均为强制条 ...

  6. Maven超细致史上最全Maven下载安装配置教学(2022更新...全版本)建议收藏...赠送IDEA配置Maven教程

    Maven安装与配置 Maven 的主要目标是让开发人员能够在最短的时间内了解开发工作的完整状态.为了实现这一目标,Maven 处理了几个关注领域: 简化构建过程 提供统一的构建系统 提供优质的项目信 ...

  7. 怎么进行多人配音?建议收藏这些方法

    相信不少小伙伴平时在网上冲浪的时候,经常会刷到一些搞笑视频吧.这些搞笑视频的配音,通常都是以一人分饰多角或者是多人互动对话的形式进行配音的.那有没有小伙伴有着不错的搞笑创意点子,但是苦于没有人配音呢? ...

  8. 微软低代码工具 Power Apps 配置不当,暴露3800万条数据记录

     聚焦源代码安全,网罗国内外最新资讯! 编译:代码卫士 Upguard 研究院称,由于微软 Power Apps 默认配置安全性薄弱,敏感数据如 COVID-19 打疫苗情况.社保号码和邮件地址遭泄露 ...

  9. 9月29 Redis配置不当致使root被提权漏洞 | Found a swap file by the name swp

    1.Redis配置不当致使root被提权漏洞 建议修复方案(需要重启redis才能生效) 1.绑定需要访问数据库的IP 修改 redis.conf 中的 "bind 127.0.0.1&qu ...

最新文章

  1. 2021-07-12 深度学习服务器网络测试(顶会ECCV网络测试)
  2. Nginx的继续深入(日志轮询切割,重写,负载均衡等)
  3. IT顾问成长分享沙龙
  4. vim 多窗口启动以及相互切换
  5. Mybatis解析动态sql原理分析
  6. git常见的回退操作
  7. [原创] 浅谈ETL系统架构如何测试?
  8. php 一个简单正则表达式,PHP中正则表达式回顾(3)--编写一个简单的正则表达式工具类...
  9. 深度学习(六十七)metal forge深度学习库使用
  10. CRM管理系统、教育后台、赠品管理、优惠管理、预约管理、试听课、教师、学生、客户、学员、商品管理、科目、优惠券、完课回访、客户管理系统、收费、退费、回访、账号权限、订单流水、审批、转账、rp原型
  11. 於岳 linux实用教程(第2版),Linux实用教程 第2版 教学课件 ppt 作者 於岳 编著 06...
  12. 《从零开始学Swift》学习笔记(Day 30)——选择类还是结构体呢?
  13. c语言实例100_pic单片机,PIC单片机C语言编程实例
  14. MonkeyTest
  15. 给大家讲解一下 AIDL原理分析
  16. Docker实时查看日志命令
  17. SAP的系统审计以及SM19的使用
  18. 关闭WIN7休眠功能
  19. IPv6地址自动配置
  20. 计算机技能大赛 英语,计算机科学与技术学院英语技能大赛圆满结束

热门文章

  1. Unity实现相机漫游功能
  2. ubuntu快捷键及Linux下一些主要目录
  3. C语言 计算cosx的近似值
  4. idea 创建一个springboot 项目(hello world)
  5. springcloud整合Gateway
  6. 语法分析程序--编译原理
  7. html css js中分号的使用
  8. 本地局域网HTTPS解决方案 CA证书
  9. 微软双拼输入法-词根速记,快速上手
  10. UI设计学习:Logo