41

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

パスワードは平文です。これを回避する方法は?

4

9 に答える 9

43

前に述べたように、パスワードを暗号化すると、問題が別の場所に移動するだけです。

とにかく、それは非常に簡単です。秘密鍵などの静的フィールドと、パスワードを暗号化、復号化するための静的メソッドを含むクラスを作成するだけです。server.xmlこのクラスを使用して、Tomcat の構成ファイル (または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;
    }
}

お役に立てれば。

于 2008-12-10T11:28:55.523 に答える
4

@Ryan が述べたように、このソリューションを実装する前に、Tomcat のTomcat Password FAQをお読みください。セキュリティではなく、あいまいさを追加しているだけです。

@Jerome Delattreの答えは、単純なJDBCデータソースでは機能しますが、データソース構築の一部として接続するより複雑なもの(例:oracle.jdbc.xa.client.OracleXADataSource)では機能しません。

これは、既存のファクトリを呼び出す前にパスワードを変更する代替アプローチです。以下は、基本的なデータソースのファクトリと、Atomikos JTA 互換の XA データソースのファクトリの例です。

基本的な例:

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

アトミコスの例:

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

参照のパスワード値の更新:

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

これらのクラスを含む .jar ファイルが Tomcat のクラスパスに配置されたら、それらを使用するように server.xml を更新できます。

<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... />
于 2016-09-02T18:44:58.280 に答える
3

Tomcat はデータベースへの接続方法を知る必要があるため、プレーン テキストのパスワードにアクセスする必要があります。パスワードが暗号化されている場合、Tomcat はそれを解読する方法を知る必要があるため、問題を別の場所に移動するだけです。

server.xml本当の問題は、Tomcat 以外の誰がアクセスできるかということです。解決策は、Tomcat を root 権限で起動する必要がある root ユーザーのみに読み取りアクセスを許可することserver.xmlです。悪意のあるユーザーがシステムで root 権限を取得した場合、データベースのパスワードを失うことは、おそらく小さな問題です。

それ以外の場合は、起動するたびにパスワードを手動で入力する必要がありますが、これが実行可能なオプションになることはめったにありません。

于 2008-09-26T15:49:07.280 に答える
2

4時間の作業の後、質問と回答を検索して解決策を得ました。@Jerome Delattre の回答に基づいて、完全なコードを示します (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://..."/>

カスタム データ ソース ファクトリ:

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

データ ソース 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;
}
于 2018-01-10T03:30:58.997 に答える
-9

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

)

于 2008-09-24T19:19:46.647 に答える