How to avoid storing passwords in the clear for tomcat's server.xml Resource definition of a DataSource?

前端 未结 9 1960

The resource definition in tomcat\'s server.xml looks something like this...



        
9条回答
  •  半阙折子戏
    2020-12-01 00:49

    As @Ryan mentioned, please read Tomcat's Tomcat Password FAQ before implementing this solution. You are only adding obscurity not security.

    @Jerome Delattre's answer will work for simple JDBC data sources, but not for more complicated ones that connect as part of the datasource construction (e.g. oracle.jdbc.xa.client.OracleXADataSource).

    This is alternative approach that modifies the password prior to calling the existing factory. Below is an example of a factory for a basic datasource and one for an Atomikos JTA compatible XA datasource.

    Basic Example:

    public class MyEncryptedPasswordFactory extends BasicDataSourceFactory {
    
        @Override
        public Object getObjectInstance(Object obj, Name name, Context context, Hashtable environment)
                throws Exception {
            if (obj instanceof Reference) {
                Reference ref = (Reference) obj;
                DecryptPasswordUtil.replacePasswordWithDecrypted(ref, "password");
                return super.getObjectInstance(obj, name, context, environment);
            } else {
                throw new IllegalArgumentException(
                        "Expecting javax.naming.Reference as object type not " + obj.getClass().getName());
            }
        }
    }
    

    Atomikos Example:

    public class MyEncryptedAtomikosPasswordFactory extends EnhancedTomcatAtomikosBeanFactory {
        @Override
        public Object getObjectInstance(Object obj, Name name, Context context, Hashtable environment)
                throws NamingException {
            if (obj instanceof Reference) {
                Reference ref = (Reference) obj;
                DecryptPasswordUtil.replacePasswordWithDecrypted(ref, "xaProperties.password");
                return super.getObjectInstance(obj, name, context, environment);
            } else {
                throw new IllegalArgumentException(
                        "Expecting javax.naming.Reference as object type not " + obj.getClass().getName());
            }
        }
    }
    

    Updating password value in Reference:

    public class DecryptPasswordUtil {
    
        public static void replacePasswordWithDecrypted(Reference reference, String passwordKey) {
            if(reference == null) {
                throw new IllegalArgumentException("Reference object must not be null");
            }
    
            // Search for password addr and replace with decrypted
            for (int i = 0; i < reference.size(); i++) {
                RefAddr addr = reference.get(i);
                if (passwordKey.equals(addr.getType())) {
                    if (addr.getContent() == null) {
                        throw new IllegalArgumentException("Password must not be null for key " + passwordKey);
                    }
                    String decrypted = yourDecryptionMethod(addr.getContent().toString());
                    reference.remove(i);
                    reference.add(i, new StringRefAddr(passwordKey, decrypted));
                    break;
                }
            }
        }
    }
    

    Once the .jar file containing these classes are in Tomcat's classpath you can update your server.xml to use them.

    
    
    
    

提交回复
热议问题