使用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="data source=(LocalDb)\MSSQLLocalDB;initial catalog=ContosoUniversity;persist security info=True;user id=WEBSC_user;password=P@ssw0rd;MultipleActiveResultSets=True;App=EntityFramework"" 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="data source=(LocalDb)\MSSQLLocalDB;initial catalog={0};persist security info=True;user id={1};password={2};MultipleActiveResultSets=True;App=EntityFramework"" />
<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是沒有載入這個參考
需要手動加入