作者个人研发在高并发场景下提供了一个简单、稳定、可扩展的延迟消息队列框架,具有精准的定时任务和延迟队列处理功能。开源半年多以来,已成功为十几家中小企业提供精准定时调度解决方案,经受住了生产环境的考验。为了造福更多的童鞋,这里给出开源框架的地址:https://github.com/sunshinelyz/mykit-delay写的比较早,有读者私信我说他们公司配置的数据库密码项目未加密,编译打包的项目被人反编译,成功从项目中获取到数据库的账号和密码,并进一步登录数据库获取相关数据,数据库被破坏。虽然这次事故的范围不大,但足以说明很多企业对项目的安全重视不够。文章已收录于:https://github.com/sunshinelyz/technology-binghehttps://gitee.com/binghe001/technology-binghe数据泄露的原因是Java项目的特殊性,如果打包后的项目没有代码混淆,如果配置文件中的重要配置信息没有加密,一旦打包后的程序被反编译,很容易获取这些敏感信息,进而对项目或系统造成一定的损害。因此,无论是公司层面还是个人开发者都需要关注项目的安全性。今天我们就来说说如何在项目中对数据库密码进行加密,尽量保证数据库密码的安全。在这篇文章中,我使用的数据库连接池是阿里开源的Druid。数据库密码加密配置数据库连接池这里我就简单的用xml配置来演示一下。当然小伙伴们也可以使用Spring注解或者SpringBoot进行配置。
注意:我在配置文件生成RSA密钥使用RSA公钥和私钥为一对公钥和私钥生成实用程序类如下所示。packagecom.binghe.crypto.rsa;importjava.security.Key;importjava.security.KeyPair;importjava.security.KeyPairGenerator;importjava.security.interfaces.RSAPrivateKey;importjava.security.interfaces.RSAPublicKey;importjava.util.HashMap;importjava。util.Map;importsun.misc.BASE64Decoder;importsun.misc.BASE64Encoder;/***算法工具类*@authorbinghe*/publicclassRSAKeysUtil{publicstaticfinalStringKEY_ALGORITHM="RSA";publicstaticfinalStringSIGNATURE_ALGORITHM="MD5withRSA";privatestaticfinalString_privateublicateKEY=RSAPUBLIC_KEY="RSA";"RSAPrivateKey";publicstaticvoidmain(String[]args){MapkeyMap;try{keyMap=initKey();StringpublicKey=getPublicKey(keyMap);System.out.println(publicKey);StringprivateKey=getPrivateKey(keyMap);System.out.println(privateKey);}catch(Exceptione){e.printStackTrace();}}publicstaticStringgetPublicKey(MapkeyMap)throwsException{Keykey=(Key)keyMap。get(PUBLIC_KEY);byte[]publicKey=key.getEncoded();returnencryptBASE64(key.getEncoded());}publicstaticStringgetPrivateKey(MapkeyMap)throwsException{Keykey=(Key)keyMap.get(PRIVATE_KEY);byte[]privateKey=key.getEncoded();returnencryptBASE64(key.getEncoded());}publicstaticbyte[]decryptBASE64(Stringkey)throwsException{return(newBASE64Decoder()).decodeBuffer(key);}publicstaticStringencryptBASE64(byte[]key)throwsException{return(newBASE64Encoder()).encodeBuffer(key);}publicstaticMapinitKey()throwsException{KeyPairGeneratorkeyPairGen=KeyPairGenerator.getInstance(KEY_ALGORITHM);keyPairGen.initialize(1024);KeyPairkeyPair=keyPairGen.generateKeyPair();RSAPublicKeypublicKey=(RSAPublicKey)keyPair.getPublic();RSAPrivateKeyprivateKey=(RSAPrivateKey)keyPair.getPrivate();MapkeyMap=newHashMap(2);keyMap.put(PUBLIC_KEY,publicKey);keyMap.put(PRIVATE_KEY,privateKey);returnkeyMap;}}运行这个类,输输出结果如下:输出结果信息中,上半部分为公钥,下半部分为私钥,用于加密密码。使用私钥对明文密码进行加密。示例代码如下。packagecom.binghe.dbsource.demo;importcom.alibaba.druid.filter.config.ConfigTools;/***使用密钥加密数据库密码的代码示例*@authorbinghe*/publicclassConfigToolsDemo{/***私钥加密数据*/privatestaticfinalStringPRIVATE_KEY_STRING="MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKtq3IJP5idDXZjML6I8HTAl0htWZSOO43LhZ/+stsIG50WsuW0UJ2vdrEtjvTEfJxP6N1VNrbsF9Lrsp6A4AyUwx00ZUueTlbUaX60134Di0IdQ3C4RTt5mPIbF3hUKers8csltgYR4fByvR3Eq4lt+jAolVHKmyzufukH3d3vJAgMBAAECgYBXiyW+r4t9NdxRMsaI9mZ5tncNWxwgAtOKUi/I1a4ofVoTrVitqoNPhVB+2BtBQQW2IC2uNROq1incZQxeuPxxZJgz1lnnZyHvDE3wuMZAGTcalID+5xBZ2j6fBtDnxbfIL/tIfGJrX+0mUXP2LIo242yQIlzr7RV60iuE2Ms54QJBAOqE0ycvztfxubqBWO7l8PsS3qDUv9lLBBO/Q8I+qVl4tzh+SD/13BqLuaj9eWPGPyml+faWtbmuQgBqauT23l0CQQC7HmMC0CgZS6taQxmPkXzw0XhxZ7tBZeLWl87hqc2S79P0BPX9kPukiC4LpA5xyz0CZ5azJXd2EwRsxF32GERdAkASEi4bJOnxZeUD5BewQPOyxR92kS4/VjJ4OxLDkwSFqnGj3sc+dnmBaibiSLXj5FDVqr56K97Q8gaP9aNLBWLZAkEAjwGnPBQoQUTinaZgl6fibA47VbiolU+v8L+u3iqvMVhXjcxo0DUJDXMCdeUZIQDqDLdsplfBGB1qqVHeWeGsBQJAXGNe2I510WLjMdn+olhi5ZjMr4F4oiF8TAE1Uu74FWn0sc418E7ScgXPCgpGVK0QaXo2wtDeMIoxJwm9Zh8oyg==";publicstaticvoidmain(String[]args)throwsException{//密码明文,也就是数据库的密码StringplainText="root";System.out.printf(ConfigTools.encrypt(PRIVATE_KEY_STRING,plainText));}}Runningtheabovecodesampleresultsinthefollowing然后将数据库配置的链接密码改为这个输出结果如下:jdbc.username=rootjdbc.password=EA9kJ8NMV8zcb5AeLKzAsL/8F1ructRjrqs69zM70BwDyeMtxuEDEVe9CBeRgZ+qEUAshhWGEDk9ay3TLLKrf2AOE3VBn+w8+EfUIEXFy8u3jYViHeV8yc8Z7rghdFShhd/IJbjqbsro1YtB9pHrl4EpbCqp7RM2rZR/wJ0WN48=编写解析数据库密码的类packagecom.binghe.dbsource;importjava.util.Properties;importcom.alibaba.druid.filter.config.ConfigTools;importcom.alibaba.druid.util.DruidPasswordCallback;/***databasepasswordcallback*@authorbinghe*/publicclassDBPasswordCallbackextendsDruidPasswordCallback{privatestaticfinallongserialVersionUID=-46011056464278的属性*/privatestaticfinalStringDB_PWD="password";/***数据对应的公钥*/publicstaticfinalStringPUBLIC_KEY_STRING="MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCratyCT+YnQ12YzC+iPB0wJdIbVmUjjuNy4Wf/rLbCBudFrLltFCdr3axLY70xHycT+jdVTa27BfS67KegOAMlMMdNGVLnk5W1Gl+tNd+A4tCHUNwuEU7eZjyGxd4VCnq7PHLJbYGEeHwcr0dxKuJbfowKJVRypss7n7pB93d7yQIDAQAB";@OverridepublicvoidsetProperties(Propertiesproperties){super.setProperties(properties);Stringpwd=properties.getProperty(DB_PWD);if(pwd!=null&&!"".equals(pwd.trim())){try{//这里的密码是配置jdbc.properties得到的密码解密后的值//所以这里的代码是解密密码//TODO解密pwd;Stringpassword=ConfigTools.decrypt(PUBLIC_KEY_STRING,pwd);setPassword(password.toCharArray());}catch(Exceptione){setPassword(pwd.toCharArray());}}}}这里的DBPasswordCallback类就是配置文件中配置的DBPasswordCallback类,如下所示PasswordCallback在javax.security.auth.callback包下。底层安全服务实例化一个PasswordCallback,传递给CallbackHandler的handle方法获取密码信息。当然除了用上面的方法,你还可以对应一套加解密方法,只需要替换Stringpassword=ConfigTools.decrypt(PUBLIC_KEY_STRING,pwd);DBPasswordCallback。另外,在编写解析数据库密码的类时,除了继承阿里巴巴开源Druid框架中的DruidPasswordCallback类外,还可以直接继承Spring提供的PropertyPlaceholderConfigurer类,如下所示。publicclassDecryptPropertyPlaceholderConfigurereextendsPropertyPlaceholderConfigurer{/***重写父类方法,解密指定属性名对应的属性值*/@OverrideprotectedStringconvertProperty(StringpropertyName,StringpropertyValue){if(isEncryptPropertyVal(propertyName)){returnDesUtils.getDecryptValueString);/property/解密方法}else{returnpropertyValue;}}/***判断属性值是否需要解密。这里我同意需要解密的属性名以encrypt*/privatebooleanisEncryptPropertyVal(StringpropertyName){if(propertyName.startsWith("encrypt")){returntrue;开头;}else{returnfalse;}}}此时需要在xml文件中修改如下配置到以下配置。至此,整个项目中数据库密码的加密解析过程就完成了。本文转载自微信公众号“冰河科技”,可通过以下二维码关注。转载本文请联系冰川科技公众号。