MySQL連接配置文件密碼加密及其在多種連接池上的應(yīng)用
為了安全,連接數(shù)據(jù)庫(kù)的配置文件中,如密碼等信息需要采用密文的形式存放。
本文將給出多種連接池?cái)?shù)據(jù)庫(kù)密碼密文存放的實(shí)現(xiàn)~
如何配置數(shù)據(jù)庫(kù)密碼加密訪問(wèn)數(shù)據(jù)庫(kù)?
將配置文件用戶相關(guān)的信息(例如:密碼)進(jìn)行加密使其以密文形式存在,進(jìn)行初始化連接池的時(shí)候進(jìn)行解密操作,達(dá)到成功創(chuàng)建連接池的目的。
接下來(lái),我們完成如下幾個(gè)連接池采用數(shù)據(jù)庫(kù)密文存儲(chǔ)的實(shí)現(xiàn):
- DBCP連接池
 - C3P0連接池
 - Druid連接池
 
DBCP連接池
數(shù)據(jù)庫(kù)屬性文件database.properties
配置數(shù)據(jù)庫(kù)屬性文件, 配置數(shù)據(jù)庫(kù)連接的密碼(jdbc.password)設(shè)置為加密后的值,該值可以采用AES、DES、3DES等對(duì)稱加密方式實(shí)現(xiàn),也可以采用RSA的加密算法存儲(chǔ)~
- # jdbc.driverClassName
 - jdbc.driverClassName=com.mysql.jdbc.Driver
 - # Database URL
 - jdbc.url=jdbc:mysql://127.0.0.1:3306/abc?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull
 - jdbc.username=abc
 - jdbc.password=YpIADNvyi+/X2O33wS5E9SaEVKZgKuS70X8kgxgioEJ7+7KccS8aVmFIWndJ83NsUebDkb+w94HM3xCyjnjg4Q==
 - # Time to wait for an open connection before timing out
 - # (in milliseconds)
 - cpool.checkoutTimeout=5000
 - # Connection pool size
 - cpool.minPoolSize=10
 - cpool.maxPoolSize=50
 - # How long to keep unused connections around(in seconds)
 - # Note: MySQL times out idle connections after 8 hours(28,800 seconds)
 - # so ensure this value is below MySQL idle timeout
 - cpool.maxIdleTime=25200
 - # How long to hang on to excess unused connections after traffic spike
 - # (in seconds)
 - cpool.maxIdleTimeExcessConnections=1800
 - # Acquiring new connections is slow, so eagerly retrieve extra connections
 - # when current pool size is reached
 - cpool.acquireIncrement=10
 
自定義CustomDataSource
如果采用DBCP連接池,那么,我們可以采用自定義連接池,繼承org.apache.commons.dbcp.BasicDataSource,然后重寫(xiě)setPassword(String password)方法即可~
- import org.apache.commons.codec.binary.Base64;
 - /**
 - * @Type CustomDataSource.java
 - * @Desc
 - * @author wangmengjun
 - * @date 2017年12月12日 下午8:50:49
 - * @version
 - */
 - public class CustomDataSource extends org.apache.commons.dbcp.BasicDataSource {
 - public CustomDataSource() {
 - super();
 - }
 - @Override
 - public void setPassword(String password) {
 - try {
 - String decodePassword = new String(Base64.decodeBase64(password.getBytes()));
 - this.password =decodePassword;
 - } catch (Exception e) {
 - }
 - }
 - }
 
上述自定義DataSource示例中,采用Base64來(lái)完成簡(jiǎn)單的加解密~
配置文件配置dataSource的地方,將org.apache.commons.dbcp.BasicDataSource改寫(xiě)成自定義連接池類名即可(如:com.xxx.datasource.CustomDataSource)~
- <bean id="dataSource" class="com.xxx.datasource.CustomDataSource"
 - destroy-method="close">
 - <property name="driverClassName" value="${jdbc.driverClassName}" />
 - <property name="url" value="${jdbc.url}" />
 - <property name="username" value="${jdbc.username}" />
 - <property name="password" value="${jdbc.password}" />
 - <!-- 可同時(shí)連接的最大的連接數(shù) -->
 - <property name="maxActive" value="60" />
 - <!-- 最大的空閑的連接數(shù) -->
 - <property name="maxIdle" value="60" />
 - <!-- 最小的空閑的連接數(shù),低于這個(gè)數(shù)量會(huì)被創(chuàng)建新的連接,默認(rèn)為0 -->
 - <property name="minIdle" value="5" />
 - <!-- 連接池啟動(dòng)時(shí)創(chuàng)建的初始化連接數(shù)量,默認(rèn)值為0 -->
 - <property name="initialSize" value="1" />
 - <!-- 等待連接超時(shí)時(shí)間,毫秒,默認(rèn)為無(wú)限 -->
 - <property name="maxWait" value="30000" />
 - </bean>
 
經(jīng)過(guò)上述幾個(gè)步驟,就可以采用密文配置數(shù)據(jù)庫(kù)密碼。
C3P0連接池
數(shù)據(jù)庫(kù)屬性文件database.properties
屬性配置文件內(nèi)容和上述DBCP連接池示例中的一致~
如果采用的C3P0連接池,那么,我們要做的是在配置com.mchange.v2.c3p0.ComboPooledDataSource的地方,增加properties屬性,編寫(xiě)一個(gè)PropertiesFactory類,實(shí)現(xiàn)password的解密操作即可~
- 編寫(xiě)CustomDatasourcePropertiesFactory類
 
- import java.util.Properties;
 - import org.apache.commons.codec.binary.Base64;
 - import org.slf4j.Logger;
 - import org.slf4j.LoggerFactory;
 - /**
 - * @Type CustomDatasourcePropertiesFactory.java
 - * @Desc
 - * @author wangmengjun
 - * @date 2017年12月12日 下午9:11:06
 - * @version
 - */
 - public class CustomDatasourcePropertiesFactory {
 - private static final String PASSWORD_PROPERTY = "password";
 - private static final Logger logger = LoggerFactory
 - .getLogger(CustomDatasourcePropertiesFactory.class);
 - public static Properties getProperties(String password) throws Exception {
 - Properties properties = new Properties();
 - try {
 - /**
 - * 解密密碼
 - */
 - String decodePassword = new String(Base64.decodeBase64(password.getBytes()));
 - properties.setProperty(PASSWORD_PROPERTY, decodePassword);
 - } catch (Exception e) {
 - logger.error("CustomDatasourcePropertiesFactory#getProperties" + e.getMessage(), e);
 - }
 - return properties;
 - }
 - }
 
采用Base64來(lái)完成密碼密文解密。
- 為ComboPooledDataSource配置名為properties的屬性
 
- <property name="properties">
 - <bean class="com.xxx.datasource.CustomDatasourcePropertiesFactory"
 - factory-method="getProperties">
 - <constructor-arg type="java.lang.String">
 - <value>${jdbc.password}</value>
 - </constructor-arg>
 - </bean>
 - </property>
 
完整示例如下:
- <!-- 配置數(shù)據(jù)源-C3PO -->
 - <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
 - destroy-method="close">
 - <property name="properties">
 - <bean class="com.xxx.datasource.CustomDatasourcePropertiesFactory"
 - factory-method="getProperties">
 - <constructor-arg type="java.lang.String">
 - <value>${jdbc.password}</value>
 - </constructor-arg>
 - </bean>
 - </property>
 - <property name="driverClass" value="${jdbc.driverClassName}" />
 - <property name="jdbcUrl" value="${jdbc.url}" />
 - <property name="user" value="${jdbc.username}" />
 - <!-- <property name="password" value="${jdbc.password}" /> -->
 - <property name="autoCommitOnClose" value="false" />
 - <property name="maxIdleTime" value="${cpool.maxIdleTime}" />
 - <property name="checkoutTimeout" value="${cpool.checkoutTimeout}" />
 - <property name="initialPoolSize" value="${cpool.minPoolSize}" />
 - <property name="minPoolSize" value="${cpool.minPoolSize}" />
 - <property name="maxPoolSize" value="${cpool.maxPoolSize}" />
 - <property name="acquireIncrement" value="${cpool.acquireIncrement}" />
 - <property name="maxIdleTimeExcessConnections" value="${cpool.maxIdleTimeExcessConnections}" />
 - </bean>
 
Druid連接池
數(shù)據(jù)庫(kù)連接屬性文件
- username=abc
 - password=YpIADNvyi+/X2O33wS5E9SaEVKZgKuS70X8kgxgioEJ7+7KccS8aVmFIWndJ83NsUebDkb+w94HM3xCyjnjg4Q==
 - url=jdbc:mysql://127.0.0.1:3306/InIot?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull
 - driver=com.mysql.jdbc.Driver
 - initialSize=5
 - minIdle=5
 - maxActive=20
 - maxWait=60000
 - timeBetweenEvictionRunsMillis=60000
 - minEvictableIdleTimeMillis=30000
 - validationQuery=SELECT 1
 - testWhileIdle=true
 - testOnBorrow=true
 - testOnReturn=true
 - filters=stat,log4j
 - removeAbandoned=true
 - removeAbandonedTimeout=1200
 - logAbandoned=true
 
實(shí)現(xiàn)密文密碼配置
在Druid連接池中密文采用RSA的方式進(jìn)行,com.alibaba.druid.filter.config.ConfigTools工具類提供了RSA的加解密功能,經(jīng)過(guò)如下2個(gè)步驟,能成密文密碼配置的功能~
- 產(chǎn)生一個(gè)密文
 
采用com.alibaba.druid.filter.config.ConfigTools完成RSA的加解密功能
ConfigTools的部分代碼如下:
- public class ConfigTools {
 - private static final String DEFAULT_PRIVATE_KEY_STRING = "MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAocbCrurZGbC5GArEHKlAfDSZi7gFBnd4yxOt0rwTqKBFzGyhtQLu5PRKjEiOXVa95aeIIBJ6OhC2f8FjqFUpawIDAQABAkAPejKaBYHrwUqUEEOe8lpnB6lBAsQIUFnQI/vXU4MV+MhIzW0BLVZCiarIQqUXeOhThVWXKFt8GxCykrrUsQ6BAiEA4vMVxEHBovz1di3aozzFvSMdsjTcYRRo82hS5Ru2/OECIQC2fAPoXixVTVY7bNMeuxCP4954ZkXp7fEPDINCjcQDywIgcc8XLkkPcs3Jxk7uYofaXaPbg39wuJpEmzPIxi3k0OECIGubmdpOnin3HuCP/bbjbJLNNoUdGiEmFL5hDI4UdwAdAiEAtcAwbm08bKN7pwwvyqaCBC//VnEWaq39DCzxr+Z2EIk=";
 - public static final String DEFAULT_PUBLIC_KEY_STRING = "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKHGwq7q2RmwuRgKxBypQHw0mYu4BQZ3eMsTrdK8E6igRcxsobUC7uT0SoxIjl1WveWniCASejoQtn/BY6hVKWsCAwEAAQ==";
 - public static void main(String[] args) throws Exception {
 - String password = args[0];
 - String[] arr = genKeyPair(512);
 - System.out.println("privateKey:" + arr[0]);
 - System.out.println("publicKey:" + arr[1]);
 - System.out.println("password:" + encrypt(arr[0], password));
 - }
 - public static String decrypt(String cipherText) throws Exception {
 - return decrypt((String) null, cipherText);
 - }
 - public static String decrypt(String publicKeyText, String cipherText)
 - throws Exception {
 - PublicKey publicKey = getPublicKey(publicKeyText);
 - return decrypt(publicKey, cipherText);
 - }
 - ... ...
 - }
 
測(cè)試一下:
- import com.alibaba.druid.filter.config.ConfigTools;
 - /**
 - * @Type ConfigToolsTest.java
 - * @Desc
 - * @author wangmengjun
 - * @date 2017年12月12日 下午1:09:38
 - * @version
 - */
 - public class ConfigToolsTest {
 - public static void main(String[] args) throws Exception {
 - String password = "abc123123";
 - String encodePassword = ConfigTools.encrypt(password);
 - System.out.println("明文密碼: " + encodePassword);
 - System.out.println("密文密碼: " + ConfigTools.decrypt(encodePassword));
 - }
 - }
 
輸出:
- 明文密碼: TcrvCxmsd2588abZpfT8DE4C1GO3rbt6S99arh1yWJC/pGjhN3vzGN182j65Ei65M00PjR+uvMC/hN12t4CxHg==
 - 密文密碼: abc123123
 
另外,也可以采用命令,獲取RSA公鑰、密鑰和密碼~
- java -cp druid-1.0.31.jar com.alibaba.druid.filter.config.ConfigTools you_password
 
如:
- F:\>java -cp druid-1.0.31.jar com.alibaba.druid.filter.config.ConfigTools abc123123
 - privateKey:MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAzvPye2JYkSLqekOHPjNWdxYsfXP2XXAsJYR2Z1zukYlchouhvYvQhNrA9r7vxtvCFZKpWbAMC7YfKM4vvyz5DwIDAQABAkAgwlDR4yFt5/8B14qi9/Fp7GKigSawZ781OSCdAALrmm+9WrPsck9klZegUnUc5ewnjC3mBoqqd5aTrRH0EZtRAiEA9RfJ4yOjTEQtl2GXUWy2uP1evxyp8hbOxPYj1TDZDasCIQDYKaZrjySu7AJ9leScDGLmUBzhWX2FeXZ0IIMHEeq2LQIhAJA6TX2yrRfmTwX0Uf2CggxeXXENRxzFOyxAxFlig3g9AiAhuAWEu7R+MMSGsI4TpX777D1FDb+dxX+rx7KItMvHFQIgaHGt2T/Qw+qJ9+GIi9/qQkUhKUK59vDYFB5j0mmkJRc=
 - publicKey:MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAM7z8ntiWJEi6npDhz4zVncWLH1z9l1wLCWEdmdc7pGJXIaLob2L0ITawPa+78bbwhWSqVmwDAu2HyjOL78s+Q8CAwEAAQ==
 - password:zctG01uijEcWQ34N9ishfOkuQtMBucDApSeD+Jrg9qOitMavrrErhrQFeBkdlf4KI7b8YCUn2O6TWa6Z6fVQQg==
 - F:\>
 
- 配置connectionProperties屬性
 
- <!-- config.decrypt=true -->
 - <property name="filters" value="config" />
 - <property name="connectionProperties" value="config.decrypt=true" />
 
詳細(xì)的數(shù)據(jù)源配置如下:
- <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
 - <property name="driverClassName" value="${driver}" />
 - <property name="url" value="${url}" />
 - <property name="username" value="${username}" />
 - <property name="password" value="${password}" />
 - <!-- config.decrypt=true -->
 - <property name="filters" value="config" />
 - <property name="connectionProperties" value="config.decrypt=true" />
 - <!-- 初始化連接大小 -->
 - <property name="initialSize" value="${initialSize}" />
 - <!-- 連接池最大使用連接數(shù)量 -->
 - <property name="maxActive" value="${maxActive}" />
 - <!-- 連接池最大空閑 這個(gè)參數(shù)已經(jīng)被棄用 -->
 - <property name="maxIdle" value="${maxIdle}"></property>
 - <!-- 連接池最小空閑 -->
 - <property name="minIdle" value="${minIdle}"></property>
 - <!-- 獲取連接最大等待時(shí)間 -->
 - <property name="maxWait" value="${maxWait}"></property>
 - <property name="validationQuery" value="${validationQuery}" />
 - <property name="testWhileIdle" value="${testWhileIdle}" />
 - <property name="testOnBorrow" value="${testOnBorrow}" />
 - <property name="testOnReturn" value="${testOnReturn}" />
 - <!-- 配置間隔多久才進(jìn)行一次檢測(cè),檢測(cè)需要關(guān)閉的空閑連接,單位是毫秒 -->
 - <property name="timeBetweenEvictionRunsMillis" value="${timeBetweenEvictionRunsMillis}" />
 - <!-- 配置一個(gè)連接在池中最小生存的時(shí)間,單位是毫秒 -->
 - <property name="minEvictableIdleTimeMillis" value="${minEvictableIdleTimeMillis}" />
 - <!-- 關(guān)閉長(zhǎng)時(shí)間不使用的連接 打開(kāi)removeAbandoned功能 -->
 - <property name="removeAbandoned" value="${removeAbandoned}" />
 - <!-- 1200秒,也就是20分鐘 -->
 - <property name="removeAbandonedTimeout" value="${removeAbandonedTimeout}" />
 - <!-- 關(guān)閉abanded連接時(shí)輸出錯(cuò)誤日志 -->
 - <property name="logAbandoned" value="${logAbandoned}" />
 - </bean>
 
可以從Druid官網(wǎng)獲取更多的信息。
【官網(wǎng)】https://github.com/alibaba/druid/wiki/使用ConfigFilter
至此,三種數(shù)據(jù)庫(kù)連接池,包括DBCP、C3P0以及Druid的密碼配置就完成了~
回顧一下:
如何配置數(shù)據(jù)庫(kù)密碼加密訪問(wèn)數(shù)據(jù)庫(kù) ?
將配置文件用戶相關(guān)的信息(例如:密碼)進(jìn)行加密使其以密文形式存在,進(jìn)行初始化連接池的時(shí)候進(jìn)行解密操作,達(dá)到成功創(chuàng)建連接池的目的。
















 
 
 



 
 
 
 