【问题标题】:How to use encrypted password in apache BasicDataSource?如何在 apache BasicDataSource 中使用加密密码?
【发布时间】:2011-03-26 06:53:16
【问题描述】:

目前我将密码 [未加密] 保存在属性文件中。使用 ant 将密码按原样放置在配置 xml 中。
[配置xml用于数据源,它正在创建dbcp.BasicDataSource的对象]

现在,是否有可能在 ant 目标之后以加密形式复制密码。听说Jasypt可以做到!直到现在我还没有尝试过这个。但是,问题并不止于此。 BasicDataSource 不接受加密密码。 BasicDatasource 有什么替代品吗?

仅供参考:我正在使用 Spring,如果这很重要的话。

【问题讨论】:

    标签: java apache encryption ant datasource


    【解决方案1】:

    BasicDataSource 的情况并不完全正确。

    如果您阅读了 BasicDataSource 的 javadocs,则一旦池初始化,setPassword() 将不起作用。第一次调用以下方法之一时初始化池:getConnectionsetLogwritersetLoginTimeoutgetLoginTimeoutgetLogWriter

    参考:http://www.docjar.com/html/api/org/apache/commons/dbcp/BasicDataSource.java.html

    所有这些方法最终都会调用createDataSource()

    所以你的新 BasicDataSource 类只需要重写方法createDataSource() 像这样的:

    public class NewBasicDataSource extends BasicDataSource {
    
        protected synchronized DataSource createDataSource() throws SQLException {
            String decryptedPassword = decryptPassword( super.getPassword() );
            super.setPassword( decryptedPassword );
            return super.createDataSource();
        }
    
        private String decryptPassword( String password ) {
            return //logic to decrypt current password
        }
    }
    

    【讨论】:

      【解决方案2】:

      通过扩展现有任务Copy(负责文件复制)创建一个新任务。通过扩展FilterSet(负责过滤令牌)创建一个新类型。
      在此处查看代码:- How to create nested element for ant task?

      build.xml

      <target name="encrypted-copy" >
              <CopyEncrypted todir="dist/xyz/config" overwrite="true">
                  <fileset dir="config"/>                 
                  <encryptionAwareFilterSet>
                      <filtersfile file="conf/properties/blah-blah.properties" />
                  </encryptionAwareFilterSet>
              </CopyEncrypted>
          </target>
      

      blah-blah.properties

      property1=value1
      property2=value2
      PASSWORD=^&YUII%%&*(
      USERNAME=rjuyal
      CONNECTION_URL=...
      someotherproperty=value
      

      配置 xml

      <bean id="dataSource"
              class="com.xyz.datasource.EncryptionAwareDataSource"
              destroy-method="close" autowire="byName">
              <property name="driverClassName">
                  <value>com.ibm.db2.jcc.DB2Driver</value>
              </property>
              <property name="url">
                  <value>@CONNECTION_URL@</value>
              </property>
              <property name="username">
                  <value>@USERNAME@</value>
              </property>
              <property name="password">
                  <value>@PASSWORD@</value>
              </property>
              <property name="poolPreparedStatements">
                  <value>true</value>
              </property>
              <property name="maxActive">
                  <value>10</value>
              </property>
              <property name="maxIdle">
                  <value>10</value>
              </property>     
          </bean>
      ...
      ...
      ...
      

      在目标执行后,xml 会与属性文件中的值一起复制。密码将被加密。

      这将处理加密的密码。 EncryptionAwareDataSource

      public class EncryptionAwareDataSource extends BasicDataSource{
          @Override
          public synchronized void setPassword(String password) {     
              super.setPassword(Encryptor.getDecryptedValue( password ));
          }
      }
      

      就是这样;)

      【讨论】:

        【解决方案3】:

        使用 Spring 有一个更好的方法:使用 PropertyPlaceholderConfigurer 类。

        <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
            <property name="locations">
                <value>classpath:com/foo/jdbc.properties</value>
            </property>
            <property name="propertiesPersister">
                <bean class="com.mycompany.MyPropertyPersister" />
            </property>        
        </bean>
        
        <bean id="dataSource" destroy-method="close"
              class="org.apache.commons.dbcp.BasicDataSource">
            <property name="driverClassName" value="${jdbc.driverClassName}"/>
            <property name="url" value="${jdbc.url}"/>
            <property name="username" value="${jdbc.username}"/>
            <property name="password" value="${jdbc.password}"/>
        </bean>
        

        当您在属性占位符中指定PropertiesPersister 的子类时,Spring 会加载jdbc.properties 并使用该类解密文件。可能是这样的:

        public class MyPropertyPersister extends DefaultPropertiesPersister
        {
            // ... initializing stuff...
        
            public void load(Properties props, InputStream is) throws IOException
            {
                Cipher decrypter = getCipher();
                InputStream cis = new CipherInputStream(is, decrypter);
                super.load(props, cis);
            }
        
            public void load(Properties props, Reader reader) throws IOException
            {
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                IOUtils.copy(reader, baos);
                ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
        
                Cipher decrypter = getCipher();
                InputStream cis = new CipherInputStream(bais, decrypter);
        
                InputStreamReader realReader = new InputStreamReader(cis);
                super.load(props, realReader);
            }
        
            public void loadFromXml(Properties props, InputStream is) throws IOException
            {
                Cipher decrypter = getCipher();
                InputStream cis = new CipherInputStream(is, decrypter);
                super.loadFromXml(props, cis);
            }
        
            private Cipher getCipher()
            {
                 // return a Cipher to read the encrypted properties file
                 ...
            }
            ...
        }
        

        希望对你有帮助。

        编辑 如果使用 Jasypt,则不需要定义任何 PropertiesPersister。来自Jasypt documentation

        Jasypt 提供了这些与配置相关的 Spring 类的实现,它可以读取具有加密值的 .properties 文件(如由 EncryptableProperties 类管理的那些),并对 Spring 应用程序 bean 的其余部分透明地处理它们。

        有了这个,你可以像这样定义jdbc.properties

         jdbc.driver=com.mysql.jdbc.Driver
         jdbc.url=jdbc:mysql://localhost/reportsdb
         jdbc.username=reportsUser
         jdbc.password=ENC(G6N718UuyPE5bHyWKyuLQSm02auQPUtm)
        

        Spring 配置可能是这样的

        <bean class="org.jasypt.spring.properties.EncryptablePropertyPlaceholderConfigurer">
           <constructor-arg>
             <bean class="org.jasypt.encryption.pbe.StandardPBEStringEncryptor">
               <property name="config">
                 <bean class="org.jasypt.encryption.pbe.config.EnvironmentStringPBEConfig">
                   <property name="algorithm" value="PBEWithMD5AndDES" />
                   <property name="passwordEnvName" value="APP_ENCRYPTION_PASSWORD" />
                 </bean>
               </property>
             </bean>
           </constructor-arg>
           <property name="locations">
             <list>
               <value>/WEB-INF/classes/jdbc.properties</value>
             </list>
           </property>   
        </bean>
        
        <bean id="dataSource" destroy-method="close"
              class="org.apache.commons.dbcp.BasicDataSource">
            <property name="driverClassName" value="${jdbc.driverClassName}"/>
            <property name="url" value="${jdbc.url}"/>
            <property name="username" value="${jdbc.username}"/>
            <property name="password" value="${jdbc.password}"/>
        </bean>
        

        这样,您可以在启动应用程序时将解密隐藏属性的密码放在环境变量中,稍后再取消设置。

        【讨论】:

        • 非常有帮助。只是一个简单的更正,在属性文件中它是 jdbc.driver 但在 bean 定义中它是 ${jdbc.driverClassName}。
        【解决方案4】:

        扩展 BasicDataSource,覆盖 setPassword 和 setUserName 方法。解密这些方法中的值并将它们传递给超类方法。

        【讨论】:

          【解决方案5】:

          以下 jasypt 链接说明了如何从您的应用程序中读取包含加密内容的属性文件:

          http://www.jasypt.org/encrypting-configuration.html

          要从 ANT 中创建属性文件,我的建议是使用 groovy 任务,如下所示:

          <taskdef name="groovy" classname="org.codehaus.groovy.ant.Groovy"/>
          
          <groovy>
          import org.jasypt.encryption.pbe.StandardPBEStringEncryptor
          
          def encryptor = new StandardPBEStringEncryptor();
          encryptor.setPassword("secret"); 
          
          def f = new File("config.properties")
          f.println "datasource.driver=com.mysql.jdbc.Driver"
          f.println "datasource.url=jdbc:mysql://localhost/reportsdb"
          f.println "datasource.username=reportsUser"
          f.println "datasource.password=ENC("+encryptor.encrypt("dbpassword")+")"    
          
          </groovy>
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2015-03-13
            • 2013-09-10
            • 1970-01-01
            • 1970-01-01
            • 2013-04-07
            • 2015-02-24
            • 1970-01-01
            • 2012-02-03
            相关资源
            最近更新 更多