usuario users reconoce por password manager habilitar desbloquear defecto contraseña configurar como application tomcat jdbc configuration

users - tomcat manager application user password



Cómo evitar el almacenamiento de contraseñas en claro para server.xml de tomcat Definición de recursos de un DataSource? (8)

La definición de recurso en server.xml de tomcat se ve más o menos así ...

<Resource name="jdbc/tox" scope="Shareable" type="javax.sql.DataSource" url="jdbc:oracle:thin:@yourDBserver.yourCompany.com:1521:yourDBsid" driverClassName="oracle.jdbc.pool.OracleDataSource" username="tox" password="toxbaby" maxIdle="3" maxActive="10" removeAbandoned="true" removeAbandonedTimeout="60" testOnBorrow="true" validationQuery="select * from dual" logAbandoned="true" debug="99"/>

La contraseña está en claro. ¿Cómo evitar esto?


Como mencionó @Ryan, lea las Preguntas frecuentes sobre la contraseña Tomcat de Tomcat antes de implementar esta solución. Solo está agregando oscuridad, no seguridad.

La respuesta de @Jerome Delattre funcionará para fuentes de datos JDBC simples, pero no para las más complicadas que se conectan como parte de la construcción del origen de datos (por ejemplo, oracle.jdbc.xa.client.OracleXADataSource).

Este es un enfoque alternativo que modifica la contraseña antes de llamar a la fábrica existente. A continuación se muestra un ejemplo de una fábrica para un origen de datos básico y otro para un origen de datos XA compatible con Atomikos JTA.

Ejemplo básico:

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()); } } }

Ejemplo de Atomikos:

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()); } } }

Actualizando el valor de la contraseña en Referencia:

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; } } } }

Una vez que el archivo .jar que contiene estas clases se encuentre en el classpath de Tomcat, puede actualizar su server.xml para usarlas.

<Resource factory="com.mycompany.MyEncryptedPasswordFactory" username="user" password="encryptedPassword" ...other options... /> <Resource factory="com.mycompany.MyEncryptedAtomikosPasswordFactory" type="com.atomikos.jdbc.AtomikosDataSourceBean" xaProperties.user="user" xaProperties.password="encryptedPassword" ...other options... />


Como se dijo antes, el cifrado de contraseñas solo está moviendo el problema a otro lugar.

De todos modos, es bastante simple. Simplemente escriba una clase con campos estáticos para su clave secreta y demás, y métodos estáticos para cifrar y descifrar sus contraseñas. Encripte su contraseña en el archivo de configuración de Tomcat ( server.xml o yourapp.xml ...) usando esta clase.

Y para descifrar la contraseña "sobre la marcha" en Tomcat, amplíe BasicDataSourceFactory del DBCP y use esta fábrica en su recurso.

Se verá así:

<Resource name="jdbc/myDataSource" auth="Container" type="javax.sql.DataSource" username="user" password="encryptedpassword" driverClassName="driverClass" factory="mypackage.MyCustomBasicDataSourceFactory" url="jdbc:blabla://..."/>

Y para la fábrica personalizada:

package mypackage; .... public class MyCustomBasicDataSourceFactory extends org.apache.tomcat.dbcp.dbcp.BasicDataSourceFactory { @Override public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable environment) throws Exception { Object o = super.getObjectInstance(obj, name, nameCtx, environment); if (o != null) { BasicDataSource ds = (BasicDataSource) o; if (ds.getPassword() != null && ds.getPassword().length() > 0) { String pwd = MyPasswordUtilClass.unscramblePassword(ds.getPassword()); ds.setPassword(pwd); } return ds; } else { return null; } }

Espero que esto ayude.


Después de 4 horas de trabajo, búsqueda de preguntas y respuestas obtuve la solución. Según la respuesta de @Jerome Delattre, aquí está el código completo (con la configuración de fuente de datos JNDI).

Context.xml

<Resource name="jdbc/myDataSource" auth="Container" type="javax.sql.DataSource" username="user" password="encryptedpassword" driverClassName="driverClass" factory="mypackage.MyCustomBasicDataSourceFactory" url="jdbc:blabla://..."/>

Fábrica de fuente de datos personalizada:

package mypackage; public class MyCustomBasicDataSourceFactory extends org.apache.tomcat.dbcp.dbcp.BasicDataSourceFactory { @Override public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable environment) throws Exception { Object o = super.getObjectInstance(obj, name, nameCtx, environment); if (o != null) { BasicDataSource ds = (BasicDataSource) o; if (ds.getPassword() != null && ds.getPassword().length() > 0) { String pwd = MyPasswordUtilClass.unscramblePassword(ds.getPassword()); ds.setPassword(pwd); } return ds; } else { return null; } } }

Fuente de datos bean:

@Bean public DataSource dataSource() { DataSource ds = null; JndiTemplate jndi = new JndiTemplate(); try { ds = jndi.lookup("java:comp/env/jdbc/myDataSource", DataSource.class); } catch (NamingException e) { log.error("NamingException for java:comp/env/jdbc/myDataSource", e); } return ds; }


Habiendo dicho todo lo anterior, si aún desea evitar las contraseñas de texto plano, puede usar un algoritmo hash como SHA-256 o (preferiblemente) SHA-512. Cuando se crea una contraseña, obtenga el valor hash y guárdelo en lugar de la contraseña. Cuando un usuario inicia sesión, compruebe la contraseña y vea si coincide con la contraseña hash almacenada. Los algoritmos hashing toman una cadena de caracteres (o número) de un espacio de cadena pequeña (o número) en uno mucho más grande de una manera que es costosa de revertir.


Tomcat necesita saber cómo conectarse a la base de datos, por lo que necesita acceso a la contraseña de texto sin formato. Si la contraseña está encriptada, Tomcat necesita saber cómo descifrarla, por lo que solo está trasladando el problema a otro lugar.

El verdadero problema es: ¿quién puede acceder a server.xml excepción de Tomcat? Una solución es dar acceso de lectura a server.xml solo al usuario raíz, lo que requiere que Tomcat se inicie con privilegios de server.xml : si un usuario malintencionado obtiene privilegios de administrador en el sistema, perder una contraseña de base de datos es probablemente una preocupación menor.

De lo contrario, debe escribir la contraseña manualmente en cada inicio, pero esto rara vez es una opción viable.


Tomcat tiene una contraseña de preguntas frecuentes que aborda específicamente su pregunta. En resumen: mantenga la contraseña en un estado claro y bloquee adecuadamente su servidor.

Esa página también ofrece algunas sugerencias de cómo la seguridad por oscuridad puede ser utilizada para aprobar una lista de verificación del auditor.


Usamos el SHA1CryptoServiceProvider de C #

print(SHA1CryptoServiceProvider sHA1Hasher = new SHA1CryptoServiceProvider(); ASCIIEncoding enc = new ASCIIEncoding(); byte[] arrbytHashValue = sHA1Hasher.ComputeHash(enc.GetBytes(clearTextPW)); string HashData = System.BitConverter.ToString(arrbytHashValue); HashData = HashData.Replace("-", ""); if (HashData == databaseHashedPassWO) { return true; } else { return false; });

)


Nota:

Puede usar WinDPAPI para cifrar y descifrar datos

public class MyDataSourceFactory extends DataSourceFactory{ private static WinDPAPI winDPAPI; protected static final String DATA_SOURCE_FACTORY_PROP_PASSWORD = "password"; @Override public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable environment) throws Exception{ Reference ref = (Reference) obj; for (int i = 0; i < ref.size(); i++) { RefAddr ra = ref.get(i); if (ra.getType().equals(DATA_SOURCE_FACTORY_PROP_PASSWORD)) { if (ra.getContent() != null && ra.getContent().toString().length() > 0) { String pwd = getUnprotectedData(ra.getContent().toString()); ref.remove(i); ref.add(i, new StringRefAddr(DATA_SOURCE_FACTORY_PROP_PASSWORD, pwd)); } break; } } return super.getObjectInstance(obj, name, nameCtx, environment); } }