1. 程式人生 > >資料來源c3p0連線 密碼加密

資料來源c3p0連線 密碼加密

(一)背景

 最近一個專案的資料來源用的dbcp,dbcp資料來源的連線密碼是加密過得,主要的加密操作是之前同事做的,查了很久,他是修改了dbcp的原始碼,修改了BasicDataSource類裡面的createConnectionFactory()方法,主要是在裡面對加密的密碼進行了解密,再建立連線。

String pwd = reset(password);
		if (pwd != null)
			connectionProperties.put("password", pwd);
		else
			log("DBCP DataSource configured without a 'password'");

然後,我們只要用他重新打包釋出的dbcp jar包就能用加過密的密碼建立資料庫連線。

現在的情況是,我想換資料來源,但是新的資料來源不想修改原始碼,同時還是使用加密的密碼做資料庫連線,這是為了防止資料庫洩露(雖然說這種方式,是防君子,不防小人)

(二)分析

通過上面的瞭解,可以修改dbcp的原始碼對加密的密碼進行解密,然後建立連線,那麼是不是也可以在不修改原始碼的情況下,攔截原始碼中建立連線時的setPassword()方法,解密後再設定。那麼,應該攔截哪個方法呢?或者說繼承

(三)測試

1.配置檔案修改

<bean id="dataSourceProperties" class="com.dooioo.datasource.PropertiesEncryptFactoryBean">  
        <property name="properties">  
            <props>  
                <prop key="user" >${${env}.boms.jdbc.username}</prop>  
                <prop key="password" >${${env}.boms.jdbc.password}</prop>  
            </props>  
        </property>  
    </bean>  
    <!--組織架構資料來源-->
     <bean id="bomsDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" >
        <property name="jdbcUrl" value="${${env}.boms.jdbc.url}"/>
        <property name="driverClass" value="${${env}.boms.jdbc.driver}"/>
         <property name="properties" ref="dataSourceProperties"/> 
       <!--  <property name="username" value="${${env}.boms.jdbc.username}"/>
        <property name="password" value="${${env}.boms.jdbc.password}"/> -->
        <!--  <property name="initialSize" value="5"/>
        <property name="maxActive" value="50"/>
        <property name="maxIdle" value="2"/>
        <property name="minIdle" value="1"/>
        <property name="defaultAutoCommit" value="true"/> -->
      
    </bean>

2.PropertiesEncryptFactoryBean(加密類) 
public class PropertiesEncryptFactoryBean implements FactoryBean{

	 private Properties properties;  
     
	    public Object getObject() throws Exception {  
	        return getProperties();  
	    }  
	  
	    public Class getObjectType() {  
	        return java.util.Properties.class;  
	    }  
	  
	    public boolean isSingleton() {  
	        return true;  
	    }  
	  
	    public Properties getProperties() {  
	        return properties;  
	    }  
	  
	    public void setProperties(Properties inProperties) {  
	        this.properties = inProperties;  
	        String originalUsername = properties.getProperty("user");  
	        String originalPassword = properties.getProperty("password");  
	        //if (originalUsername != null){  
	        //    String newUsername = deEncryptUsername(originalUsername);  
	            properties.put("user", originalUsername);  
	       // }  
	        if (originalPassword != null){  
	            String newPassword;
				try {
					newPassword = reset(originalPassword);
					properties.put("password", newPassword);  
				} catch (InvalidKeyException | SQLNestedException
						| NoSuchAlgorithmException | NoSuchPaddingException
						| IllegalBlockSizeException | BadPaddingException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}  
	            
	        }  
	    }  
	      
	    private String deEncryptUsername(String originalUsername){  
	        return deEncryptString(originalUsername);  
	    }  
	      
	    private String deEncryptPassword(String originalPassword){  
	        return deEncryptString(originalPassword);  
	    }  
	    //簡單加密  
	    private String deEncryptString(String originalString){  
	        StringBuilder newString = new StringBuilder();  
	        for (int i = 0; i < originalString.length(); i++) {  
	            char eachChar= originalString.charAt(i);  
	            char newChar = (char)(eachChar + i);  
	            newString.append(newChar);  
	        }  
	        return newString.toString();  
	    }  
	    
	    private String reset(String secret)
				throws SQLNestedException, NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, InvalidKeyException
			{
				byte decode[];
				byte kbytes[] = "TjE5MGQ5".getBytes();
				SecretKeySpec key = new SecretKeySpec(kbytes, "Blowfish");
				BigInteger n = new BigInteger(secret, 16);
				byte encoding[] = n.toByteArray();
				Cipher cipher = Cipher.getInstance("Blowfish");
				cipher.init(2, key);
				decode = cipher.doFinal(encoding);
				return new String(decode);
			}
}

這裡使用的加密解密演算法是Cipher,因為我們需要的加密解密的密碼是一樣的,所以需要使用對稱的加密解密演算法。

測試下來,這樣是可以的。

(四)總結

這種方式是主要是利用了spring載入順序,因為在載入c3p0載入之前先對配置檔案中的密碼進行相應的解密,並且注入到屬性password中,這樣在建立c3p0連線的時候,用的密碼就是明文密碼了。

這裡的資料來源安全機制感覺還不是很靠譜,下面需要試驗更改原始碼。