1. 程式人生 > >如何實現資料庫連線的密碼加密

如何實現資料庫連線的密碼加密

 專案需求 :

所有認證資料,例如密碼,不論是在儲存、傳輸中都必須妥善保護,以防洩露或被未獲授權修改。在安全認證中的Fortify 靜態程式碼分析器的掃描中,如果密碼明文放在檔案中是肯定過不去的。


需求解決方案:
下面具體結合SSH的框架的程式碼實現。
1. 認證資料加密
所有認證資料通過 3DES 加密;加解密方法如下:

Java程式碼 1.import java.security.Key;
import java.security.SecureRandom;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

public class DesEncrypt {
 /**
  *
  * 使用DES加密與解密,可對byte[],String型別進行加密與解密 密文可使用String,byte[]儲存.
  *
  * 方法: void getKey(String strKey)從strKey的字條生成一個Key
  *
  * String getEncString(String strMing)對strMing進行加密,返回String密文 String
  * getDesString(String strMi)對strMin進行解密,返回String明文
  *
  *byte[] getEncCode(byte[] byteS)byte[]型的加密 byte[] getDesCode(byte[]
  * byteD)byte[]型的解密
  */

 Key key;

 /**
  * 根據引數生成KEY
  *
  * @param strKey
  */
 public void getKey(String strKey) {
  try {
   KeyGenerator _generator = KeyGenerator.getInstance("DES");
   _generator.init(new SecureRandom(strKey.getBytes()));
   this.key = _generator.generateKey();
   _generator = null;
  } catch (Exception e) {
   e.printStackTrace();
  }
 }

 /**
  * 加密String明文輸入,String密文輸出
  *
  * @param strMing
  * @return
  */
 public String getEncString(String strMing) {

  byte[] byteMi = null;
  byte[] byteMing = null;
  String strMi = "";
  BASE64Encoder base64en = new BASE64Encoder();
  try {
   byteMing = strMing.getBytes("UTF8");
   byteMi = this.getEncCode(byteMing);
   strMi = base64en.encode(byteMi);
  } catch (Exception e) {
   e.printStackTrace();
  } finally {
   base64en = null;
   byteMing = null;
   byteMi = null;
  }
  return strMi;
 }

 /**
  * 解密 以String密文輸入,String明文輸出
  *
  * @param strMi
  * @return
  */
 public String getDesString(String strMi) {
  BASE64Decoder base64De = new BASE64Decoder();
  byte[] byteMing = null;
  byte[] byteMi = null;
  String strMing = "";
  try {
   byteMi = base64De.decodeBuffer(strMi);
   byteMing = this.getDesCode(byteMi);
   strMing = new String(byteMing, "UTF8");
  } catch (Exception e) {
   e.printStackTrace();
  } finally {
   base64De = null;
   byteMing = null;
   byteMi = null;
  }
  return strMing;
 }

 /**
  * 加密以byte[]明文輸入,byte[]密文輸出
  *
  * @param byteS
  * @return
  */
 private byte[] getEncCode(byte[] byteS) {
  byte[] byteFina = null;
  Cipher cipher;
  try {
   cipher = Cipher.getInstance("DES");
   cipher.init(Cipher.ENCRYPT_MODE, key);
   byteFina = cipher.doFinal(byteS);
  } catch (Exception e) {
   e.printStackTrace();
  } finally {
   cipher = null;
  }
  return byteFina;
 }

 /**
  * 解密以byte[]密文輸入,以byte[]明文輸出
  *
  * @param byteD
  * @return
  */
 private byte[] getDesCode(byte[] byteD) {
  Cipher cipher;
  byte[] byteFina = null;
  try {
   cipher = Cipher.getInstance("DES");
   cipher.init(Cipher.DECRYPT_MODE, key);
   byteFina = cipher.doFinal(byteD);
  } catch (Exception e) {
   e.printStackTrace();
  } finally {
   cipher = null;
  }
  return byteFina;
 }

 public static void main(String[] args) {
  System.out.println("des demo");
  DesEncrypt des = new DesEncrypt();// 例項化一個對像
  des.getKey("MYKEY");// 生成密匙
  System.out.println("key=MYKEY");
  String strEnc = des.getEncString("111111");// 加密字串,返回String的密文
  System.out.println("密文=" + strEnc);
  String strDes = des.getDesString(strEnc);// 把String 型別的密文解密
  System.out.println("明文=" + strDes);
 }
}

2. hibernate 資料庫連線密碼處理
將Hibernate 的資料庫連線密碼加密放在配置檔案和資料庫中,具體spring+hibernate 連線配置修改連線如下:

步驟1: 將spring 關於資料來源的連線修改如下:

Java程式碼 1.<bean id="dataSource" class="com.hqlTest.MyBasicDataSource" destroy-method="close">  
2. 
3.        <property name="driverClassName">  
4. 
5.            <value>oracle.jdbc.driver.OracleDriver</value>  
6. 
7.        </property>  
8. 
9.        <property name="url">  
10. 
11.            <value>jdbc:oracle:thin:@dbServer:1521:feelview</value>  
12. 
13.        </property>  
14. 
15.        <property name="username">  
16. 
17.            <value>feelview</value>  
18. 
19.        </property>  
20. 
21.        <property name="password">  
22. 
23.            <value>%QX7N顴服簹吩d/?</value>  
24. 
25.        </property>  
26. 
27.    </bean> 
<bean id="dataSource" class="com.ncs.pki.util.MyBasicDataSource" destroy-method="close">

        <property name="driverClassName">

            <value>oracle.jdbc.driver.OracleDriver</value>

        </property>

        <property name="url">

            <value>jdbc:oracle:thin:@dbServer:1521:feelview</value>

        </property>

        <property name="username">

            <value>feelview</value>

        </property>

        <property name="password">

            <value>${jdbc.password}value>

        </property>

    </bean> 

解析:

dataSource 的 class 由 org.apache.commons.dbcp.BasicDataSource 改為自己建立的 com.hqlTest.MyBasicDataSource ;

BasicDataSource 類所做的事只有二件:1,繼承 BasicDataSource ;2 ,重寫 (override) 密碼設定方法 setPassword ;函式 setPassword 中實現密碼的 3DES 解密;

MyBasicDataSource程式碼:

import java.sql.SQLException;
import org.apache.commons.dbcp.BasicDataSource;

public class MyBasicDataSource extends BasicDataSource {

 @Override
 public synchronized void setPassword(String password) {
  //讀取jdbc.Properties配置檔案中加密後的密碼
  PropertiesUtils pro=new PropertiesUtils();
  pro.getFile("jdbc.properties");
  String passwordEncString=pro.read("jdbc.password");
  pro.close();
  System.out.println("password-->"+passwordEncString);
  //將密碼解密
  DesEncrypt des=new DesEncrypt();
  des.getKey("MYKEY");//生成密匙
  password= des.getDesString(passwordEncString);// 把String 型別的密文解密
  System.out.println("明文=" + password);
  super.setPassword(password);
 }

 /**
  * @param args
  */
 public static void main(String[] args) {
  // TODO Auto-generated method stub
  MyBasicDataSource mbds=new MyBasicDataSource();
  System.out.println(mbds.getPassword());
 }

}

3.PropertiesUtils:

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Properties;

import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;

public class PropertiesUtils {
 /**
  * ???? 2006 2006-8-18 ????01:40:49
  * 得到檔案的輸入流
  **/
 private static Properties file = new Properties(); 
 public void getFile(String fileName){
//  Resource resource=new ClassPathResource(fileName);
  InputStream inputStream = getClass().getResourceAsStream("/"+fileName);
  if(inputStream==null){
   System.out.println(fileName+" is  exist!");
  }
  else{
   try {
    file.load(inputStream);
    inputStream.close();
   } catch (IOException e) {
    e.printStackTrace();
   }
  }
 }
 /**
  * @param propertyName  讀取 和寫入
  * @return  key
  */
 public String read(String propertyName){
  return  file.getProperty(propertyName);
 }
 public void write(String name,String value){
  file.setProperty(name, value);
 }
 
 /**
  * 關閉檔案
  */
 public void close(){
  try {
   OutputStream os=new FileOutputStream("jdbc.properties");
   file.store(os,null);
   /*OutputStream os=new FileOutputStream("src/jdbc.xml");
   prop.storeToXML(os,null);*/
   os.close();
  }catch (Exception e) {
   System.out.println("jdbc.properties無法正常關閉");
  }
 }
 /**
  * 測試
  */
 public static void main(String[] args){
  PropertiesUtils util = new PropertiesUtils();
  util.getFile("jdbc.properties");
  util.write("jdbc.port","10080");
  util.write("jdbc.username","9999");
  util.close();
  String value=util.read("jdbc.url");
  System.out.println("value-->"+value);
 }
}


jdbc.Properties :

jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/test
jdbc.username=root
jdbc.password=Ey4pNYUPLxE=

==========================================

住:如果是在linux系統下面,會出現登入不上的異常,

修改DesEncrypt.java類中的getkey方法:

    /**
      * 根據引數生成KEY
      *
      * @param strKey
      */
     public void getKey(String strKey) {
      try {
       KeyGenerator _generator = KeyGenerator.getInstance("DES");
//       _generator.init(new SecureRandom(strKey.getBytes()));
       SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG" );  
       secureRandom.setSeed(strKey.getBytes());  

       _generator.init(secureRandom);  
       
       this.key = _generator.generateKey();
       _generator = null;
      } catch (Exception e) {        
          e.printStackTrace();
      }
     }
     原因是

SecureRandom 實現完全隨作業系統本身的內部狀態,除非呼叫方在呼叫 getInstance 方法之後又呼叫了 setSeed 方法;該實現在 windows 上每次生成的 key 都相同,但是在 solaris 或部分 linux 系統上則不同。 參考:http://blog.csdn.net/hbcui1984/article/details/5753083