Entity Framework 連線字串加密

  • 2832
  • 0

使用EF的時候,將連線到DB的字串加密

本功能是參考黑暗大的這篇文章 為EF連線字串加密的簡單範例 實作而成

如果看不懂我寫的,歡迎拜讀黑暗大的原作。

 

首先準備好加解密的cs檔(備註一),

(個人建議除了專案自己本身有這個CS檔之外,可以寫一個簡單的winForm小程式去加解密字串)

要測試的專案是要使用EF連線到DB:ContosoUniversity

下圖為使用VS工具建立EF自動產生的ContosoUniversityEntities,

這些程式碼是由範本自動產生的,不需要去調整

Create 一個 ContosoUniversityEntities 的 partial class ,新增一個有連線字串的Constructor

注意Namespace要跟上圖原生的 ContosoUniversityEntities Namsspace一樣!

public partial class ContosoUniversityEntities
{
   public ContosoUniversityEntities(string cnStr) : base(cnStr)
   {

   }
}

 

之後開始改寫App.Config (如果是Web ,則改寫Web.Config)

<!--原本EF使用的連線字串-->
<connectionStrings>
    <add name="ContosoUniversityEntities" connectionString="metadata=res://*/ContosoUniversity.csdl|res://*/ContosoUniversity.ssdl|res://*/ContosoUniversity.msl;provider=System.Data.SqlClient;provider connection string=&quot;data source=(LocalDb)\MSSQLLocalDB;initial catalog=ContosoUniversity;persist security info=True;user id=WEBSC_user;password=P@ssw0rd;MultipleActiveResultSets=True;App=EntityFramework&quot;" providerName="System.Data.EntityClient" />    
  </connectionStrings>

<!--加密後的連線字串-->
<appSettings>
    <add key="db_ConnectionStr" value="metadata=res://*/ContosoUniversity.csdl|res://*/ContosoUniversity.ssdl|res://*/ContosoUniversity.msl;provider=System.Data.SqlClient;provider connection string=&quot;data source=(LocalDb)\MSSQLLocalDB;initial catalog={0};persist security info=True;user id={1};password={2};MultipleActiveResultSets=True;App=EntityFramework&quot;" />
    <add key="db_Catalog" value="9hGzMHTLW1ke7o65E/nbii+t17nwWHuAi0AOFzzCPoc=" /><!--加密後的連線DB-->
    <add key="db_User" value="TMWBZ3mGppxSq/c66Prfdg==" /><!--加密後的登入帳號-->
    <add key="db_Pwd" value="cFTB9cm607nbARWsFVff3Q==" /><!--加密後的密碼-->
</appSettings>

新增一個類別來專門處理連線字串的解密:

在這裡要注意 ConfigurationManager的參考問題(備註二)

public class Commountity
{
	public static ContosoUniversityEntities CreateDBContext()
	{
        //加解密的class
		MyEncrypt myEncrypt = new MyEncrypt();

        //從App.Config(or Web.Config)取出的設定加密字串,並解密
		String db_Catalog = myEncrypt.Decrypt(ConfigurationManager.AppSettings["db_Catalog"]);
		String db_User = myEncrypt.Decrypt(ConfigurationManager.AppSettings["db_User"]);
		String db_Pwd = myEncrypt.Decrypt(ConfigurationManager.AppSettings["db_Pwd"]);

		string db_ConnectionStr = string.Format(ConfigurationManager.AppSettings["db_ConnectionStr"], db_Catalog, db_User, db_Pwd);

        //回傳上面我自訂的ContosoUniversityEntities Constructor(有參數)
		return new ContosoUniversityEntities(db_ConnectionStr);
	}
}

 

接下來就是改變原本程式內呼叫EF的寫法

//原本無加解密的寫法
using (ContosoUniversityEntities db = new ContosoUniversityEntities())
{
   //LINQ處理邏輯
}

//改寫從 Commountity.CreateDBContext 取得
using (ContosoUniversityEntities db = Commountity.CreateDBContext())
{
   //LINQ處理邏輯
}

 

 

備註一 加解密的cs檔

using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

namespace DemoBatchJob
{
    class MyEncrypt
    {
        /// <summary>
        /// key 長度可為:128bit or 192 bit or 256 bit
        /// </summary>
        public static string key = "MEGASSO_MEGASSO_MEGASSO_MEGASSO_";
        /// <summary>
        /// IV( Initialization Vector) 長度固定為 128 bit
        /// </summary>
        public static string iv = "MEGASSO_MEGASSO_";

        /// <summary>
        /// Encrypt 將文字加密回傳暗碼
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public String Encrypt(String data)
        {
            if (!String.IsNullOrWhiteSpace(data))
            {
                byte[] encrypted;
                // Create an Rijndael object
                using (Rijndael rijAlg = Rijndael.Create())
                {
                    rijAlg.Key = Encoding.UTF8.GetBytes(key);
                    rijAlg.IV = Encoding.UTF8.GetBytes(iv);

                    //在衍生類別中覆寫時,使用指定的 System.Security.Cryptography.SymmetricAlgorithm.Key 屬性和初始化向量
                    //(System.Security.Cryptography.SymmetricAlgorithm.IV) 建立對稱加密子物件。
                    // create a encrypt to perform the stream transform
                    ICryptoTransform encryptor = rijAlg.CreateEncryptor(rijAlg.Key, rijAlg.IV);

                    // Create the streams used for encryption.
                    using (MemoryStream msEncrypt = new MemoryStream())
                    {
                        using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
                        {
                            using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
                            {

                                //Write all data to the stream.
                                swEncrypt.Write(data.Trim());
                            }
                            encrypted = msEncrypt.ToArray();
                        }
                    }
                }
                return Convert.ToBase64String(encrypted);
            }

            return "";
        }

        /// <summary>
        /// 將暗碼轉成明碼
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public String Decrypt(String data)
        {
            if (!String.IsNullOrWhiteSpace(data))
            {
                String plaintext = "";

                using (Rijndael rijAlg = Rijndael.Create())
                {
                    byte[] cipherText = Convert.FromBase64String(data);

                    rijAlg.Key = Encoding.UTF8.GetBytes(key);
                    rijAlg.IV = Encoding.UTF8.GetBytes(iv);

                    ICryptoTransform decryptor = rijAlg.CreateDecryptor(rijAlg.Key, rijAlg.IV);
                    // Create the streams used for decryption.
                    using (MemoryStream msDecrypt = new MemoryStream(cipherText))
                    {
                        using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
                        {
                            using (StreamReader srDecrypt = new StreamReader(csDecrypt))
                            {

                                // Read the decrypted bytes from the decrypting stream
                                // and place them in a string.
                                plaintext = srDecrypt.ReadToEnd();
                            }
                        }
                    }
                }

                return plaintext;
            }
            return "";
        }
    }
}

 

備註二:

ConfigurationManager.AppSettings["XXX"] => 預設的WinForm是沒有載入這個參考

需要手動加入