为了保护 Server.xml 文件中的密码,我在其中加密了密码并覆盖了 org.apache.coyote.http11.Http11Nio2Protocol: ,如下所示:
Server.xml 看起来像这样:
<Resource name="jdbc/HasanDB" auth="Container" type="javax.sql.DataSource"
maxTotal="10" maxIdle="15" minIdle="3" initialSize="2" maxWaitMillis="10000"
removeAbondend="true" removeAbondendTimeout="300"
username="hasan" password="<encryptedpass>" driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/HasanDB"/>
package hasan;
public class Http11Nio2Protocol extends org.apache.coyote.http11.Http11Nio2Protocol {
@Override
public void setKeystorePass(String certificateKeystorePassword) {
try {
System.out.println("..............===============certificateKeystorePassword===========................");
super.setKeystorePass(EncryptService.decrypt(certificateKeystorePassword));
} catch (final Exception e){
super.setKeystorePass("");
}
}
}
package hasan;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
public class EncryptService {
private static SecretKeySpec createSecretKey(char[] password, byte[] salt, int iterationCount, int keyLength) throws NoSuchAlgorithmException, InvalidKeySpecException {
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA512");
PBEKeySpec keySpec = new PBEKeySpec(password, salt, iterationCount, keyLength);
SecretKey keyTmp = keyFactory.generateSecret(keySpec);
return new SecretKeySpec(keyTmp.getEncoded(), "AES");
}
private static byte[] base64Decode(String property) throws IOException {
return Base64.getDecoder().decode(property);
}
static String decrypt(String string) throws GeneralSecurityException, IOException {
String password = "password";
byte[] salt = new String("salt").getBytes();
int iterationCount = 100;
int keyLength = 128;
SecretKeySpec key = createSecretKey(password.toCharArray(),
salt, iterationCount, keyLength);
String iv = string.split(":")[0];
String property = string.split(":")[1];
Cipher pbeCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
pbeCipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(base64Decode(iv)));
return new String(pbeCipher.doFinal(base64Decode(property)), "UTF-8");
}
}
我已经把上面代码的Jar文件放到了tomcat_home/lib文件夹下。
当我运行 tomcat 8.5 服务器时,上面代码中的 setKeystorePass 方法没有执行。
我必须做什么才能让它正常?
最佳答案
- 配置您的数据源
<Resource name="jdbc/yourDB"
auth="Container"
type="javax.sql.DataSource"
driverClassName="com.microsoft.sqlserver.jdbc.SQLServerDriver"
factory="org.junjun.util.secured.resources.datasource.EncryptedDataSourceFactory"
url="e6nNC2NVXThPKSyKMvCiZTa4beL/BHxyu+188EeeNWq10ynepC2f4fXHzlKKdo9288uNOStZwa6Ztu0h7TrWVAJIrurKQkfO"
username="PzyHPd4xkXJYvoN6ztoLWg=="
password="zeBxd99nNw2Hg6f4g/Rt8PkB7+uHOwVD"
maxActive="20"
maxIdle="10"
maxWait="-1" />
<ResourceLink name="jdbc/yourDB" global="jdbc/yourDB" type="javax.sql.DataSource" />
</Context>
创建您自己的数据源工厂
包 org.junjun.util.secured.resources.datasource;
import java.util.Enumeration; import java.util.Hashtable; import javax.naming.Context; import javax.naming.Name; import javax.naming.RefAddr; import javax.naming.Reference; import javax.naming.StringRefAddr; import org.apache.commons.dbcp.BasicDataSourceFactory; import org.jasypt.encryption.pbe.StandardPBEStringEncryptor; public class EncryptedDataSourceFactory extends BasicDataSourceFactory { private String USERNAME_TAG = "username"; private String PASSWORD_TAG = "password"; private String URL_TAG = "url"; private StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor(); private String password = System.getenv("secret-key"); public EncryptedDataSourceFactory() { encryptor.setPassword(this.password); } @Override public Object getObjectInstance(Object obj, Name name, Context ctx, Hashtable env) throws Exception { if (obj instanceof Reference) { setUsername((Reference) obj); setPassword((Reference) obj); setURL((Reference) obj); } return super.getObjectInstance(obj, name, ctx, env); } private void setUsername(Reference ref) { findDecryptAndReplace(USERNAME_TAG, ref); } private void setPassword(Reference ref) { findDecryptAndReplace(PASSWORD_TAG, ref); } private void setURL(Reference ref) { findDecryptAndReplace(URL_TAG, ref); } private void findDecryptAndReplace(String refType, Reference ref) { Integer idx = find(refType, ref); if (idx == null) { System.out.println("The \"" + refType + "\" name/value pair was not found" + " in the Reference object. The reference Object is" + " " + ref.toString()); } else { String decrypted = decrypt(ref.get(refType).getContent().toString()); replace(idx, refType, decrypted, ref); } } private void replace(int idx, String refType, String newValue, Reference ref) { ref.remove(idx); ref.add(idx, new StringRefAddr(refType, newValue)); } private String decrypt(String input) { return encryptor.decrypt(input); } private Integer find(String addrType, Reference ref) { Integer index = null; Enumeration<RefAddr> enu = ref.getAll(); for (int i = 0; enu.hasMoreElements(); i++) { RefAddr addr = (RefAddr) enu.nextElement(); if (addr.getType().compareTo(addrType) == 0) index = i; } return index; } }
将您自己的数据源工厂构建到 Jar 文件中
- 复制 Jar 文件到 Tomcat
- 启动Tomcat
关于java - 在 tomcat server.xml 中保护密码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45636379/