如何避免在tomcat的server.xml数据源的资源定义中明文存储密码?

时间:2020-03-06 14:40:58  来源:igfitidea点击:

tomcat的server.xml中的资源定义看起来像这样...

<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"/>

密码是明文的。如何避免这种情况?

解决方案

我们使用C#的SHA1CryptoServiceProvider

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

)

Tomcat需要知道如何连接到数据库,因此需要访问纯文本密码。如果密码是加密的,则Tomcat需要知道如何解密它,因此我们只是将问题移到了其他地方。

真正的问题是:除了Tomcat之外,谁还能访问server.xml?一种解决方案是仅向root用户授予对server.xml的读取访问权限,这要求Tomcat以root特权启动:如果恶意用户在系统上获得root特权,则丢失数据库密码可能是一个小问题。

否则,我们应该在每次启动时手动键入密码,但这很少是一个可行的选择。

如前所述,加密密码只是将问题转移到其他地方。

无论如何,这很简单。
只需编写一个类,其中包含用于密钥的静态字段等,以及用于加密,解密密码的静态方法。
使用此类将密码加密在Tomcat的配置文件(" server.xml"或者" yourapp.xml" ...)中。

为了在Tomcat中"即时"解密密码,请扩展DBCP的BasicDataSourceFactory并在资源中使用该工厂。

它看起来像:

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

对于定制工厂:

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

希望这可以帮助。