如何实现 Tomcat 连接池数据库密码加密
润乾报表应用在 tomcat 应用服务器进行部署时,如果需要调用 tomcat 配置好的数据库连接池,就不得不把报表数据源连接的密码以明文形式暴露,这样数据库连接的用户名密码都非常容易被获取,是非常不安全的。本文将介绍如何对 tomcat 数据库连接池配置文件中的密码进行加密处理。
问题解决思路:
将配置文件用户相关的信息 (例如:密码) 进行加密使其以密文形式存在,进行初始化连接池的时候进行解密操作,达到成功创建连接池的目的。Tomcat 默认使用 DBCP 连接池(基于 common-pool 的一种连接池实现),可在http://jakarta.apache.org/commons/dbcp/下载 commons-dbcp 源码包 commons-dbcp-1.4-src.zip,对 org.apache.commons.dbcp.BasicDataSourceFactory 类修改,把数据库密码字段(加密后的密文)用解密程序解密,获得解密后的明文即可。
具体实现:
1. 修改 org.apache.commons.dbcp.BasicDataSourceFactory 类文件
找到数据源密码设置部分
value = properties.getProperty(PROP_PASSWORD);
if (value != null) {
dataSource.setPassword(value);
}
修改为:
value = properties.getProperty(PROP_PASSWORD);
if (value != null) {
dataSource.setPassword(Encode.decode(value));
}
将配置文件中的“密码”(加密后的结果)取出,调用加解密类中的解密方法 Encode.decode(value) 进行解密。
2. 加密类 Encode.java, 本例中使用加密解密模块比较简单只是用来说明问题,密文为明文的十六进制串。
public class Encode {
// 编码 - 普通字符串转为十六进制字符串
public static String encode(String password){
String result = “”;
byte[] psd = password.getBytes();
for(int i=0;i<psd.length;i++){
result += Integer.toHexString(psd_&0xff);
}
return result;
}
// 解码–十六进制字符串转为普通字符串
public static String decode(String password){
String result = “”;
password = password.toUpperCase();
int length = password.length() / 2;
char[] hexChars = password.toCharArray();
byte[] d = new byte[length];
for (int i = 0; i < length; i++) {
int pos = i * 2;
d_= (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));
}
result = new String(d);
return result;
}
// 字符转字节
public static byte charToByte(char c) {
return (byte) “0123456789ABCDEF”.indexOf(c);
}
}
3. 数据库连接池文件,红色字体为数据源配置中密码设置,此时已经改为密文形式。
password
696e65743231
url
jdbcracle:thin127.0.0.1:1521rcl
driverClassName
oracle.jdbc.driver.OracleDriver
username
wanfang
4. 将修改后的 BasicDataSourceFactory.java 和新添加的 Encode.java 编译后的 class 类文件重新打包进 commons-dbcp-1.4.jar,将该包拷贝进 tomcat 下的 common/lib 目录中,重启 tomcat。此时 tomcat 下部署的应用在连接数据源的时候都可以在不暴露密码明文的情况下进行连接。
问题补充:
1. 本例中用仅使用简单的加解密算法进行密文和明文的转化,可根据具体情况选择不同的加解密模块如 MD5,base64,DES 等。
2. 本例的实现中所有的连接池初始化操作均采用相同的加密解密方法,tomcat 之下部署的应用可能是多个,强迫使用同一种方式不符合实际情形。可能出现以下场景:A_1 项目利用 B_1 加解密模块,A_2 项目利用 B_2 加解密模块,A_3 项目不利用加解密模块等等,以上方式明显无法处理。BasicDataSourceFactory.java 实现了接口 javax.naming.spi.ObjectFactory,我们也实现该接口初始内容保持和 BasicDataSourceFactory.java 相同即可。只要可以在配置文件中控制加载当前配置文件类,即可达到加解密的目的。查阅 JNDI 设置相关知识发现 Resource 中有个参数 factory,可以指定加载当前配置文件的类,若没有指定则默认采用 BasicDataSourceFactory.java。也就是我们在设置不同数据库连接池时可以指定 Resource 的 factory 为不同,这样就可以实现不同应用采用不同的加密解密模块 __