連線字串加密的方式

通常網站都會與資料庫溝通,也因此在 csharp 的專案設定檔,我們大都會將連線字串寫在這裡,便於程式調用,但資料庫連線字串包含了帳號密碼,直接寫在設定組態檔是一個資安漏洞
為了不要讓明碼直接暴露出去,我們這裡最好做一些防護措施,利用演算法將明文加密,等到要用的時候再解密出來。

當然這樣的做法還是有風險的,因為加解密的 Key、IV 也還是一樣都放在組態檔內,所以這只能說是一個初步的防護方式

連線字串加密

先透過一組金鑰 (public key, private key)來作加密、解密,有興趣的可以透過Online RSA Encryption, Decryption And Key Generator Tool來測試一下

需要先將需要保護的連線字串加密,然後將這個加密過後的字串,放到web.config裡面,等到程式需要資料庫連線的時候,取得加密字串後再針對他進行解密即可,搭配上 web.config 的連線字串lockItem設定使用。思路已經有了,所以具體的步驟大概就是要做

  1. Key、IV
  2. 加解密函式
  3. 判斷是否需要執行解密

Key、IV

這邊直接使用網路上的範例,相關知識可以參考一下這兩篇文章

  1. Day14 資料使用安全(保護連接字串)上
  2. 資料的加密與解密(1)-對稱金鑰加密演算法

config 設定

1
2
3
4
5
<?xml version="1.0" encoding="utf-8"?>
<appSettings>
<add key="hashKey" value="金鑰喔金鑰喔金鑰喔金鑰喔"/>
<add key="iv" value="加密向量初始資料"/>
</appSettings>

加解密函式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public string Decryption(string CipherText,string hashKey,string iv)
{
using (Aes aesAlg = Aes.Create())
{
aesAlg.Key = Encoding.Unicode.GetBytes(hashKey);
aesAlg.IV = Encoding.Unicode.GetBytes(iv);
ICryptoTransform decrypt = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
byte[] decrypted = decrypt.TransformFinalBlock(Convert.FromBase64String(CipherText), 0, Convert.FromBase64String(CipherText).Length);
return Encoding.Unicode.GetString(decrypted);
}
}

public string Encryption(string PlainText,string hashKey, string iv)
{
using (Aes aesAlg = Aes.Create())
{
aesAlg.Key = Encoding.Unicode.GetBytes(hashKey);
aesAlg.IV = Encoding.Unicode.GetBytes(iv);
ICryptoTransform encrypt = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
byte[] encrypted = encrypt.TransformFinalBlock(Encoding.Unicode.GetBytes(PlainText), 0,
Encoding.Unicode.GetBytes(PlainText).Length);
return Convert.ToBase64String(encrypted);
}
}

判斷是否需要執行解密

直接取得連線字串的 function 當中判斷處理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
private string GetVersion()
{
var connectionString = GetConnectionString("db");
var commandText = "select @@version";
using (var cnn = new MySqlConnection(connectionString))
{
return cnn.Query<string>(commandText).FirstOrDefault();
}
}

public string GetConnectionString(string name)
{
var connectionString = ConfigurationManager.ConnectionStrings[name];
var source = connectionString.ConnectionString;
if (connectionString.LockItem)
{
var hashKey = ConfigurationManager.AppSettings["hashKey"];
var iv = ConfigurationManager.AppSettings["iv"];
source = Decryption(source, hashKey, iv);
}
return source;
}

Sample Code


Github

組態檔案加密

透過 aspnet_regiis.exe 來處理,需要透過管理員權限來執行喔

1
2
3
4
5
# 透過 aspnet_regiis將 指定目錄下的 web.config 當中的 appSettings 區段加密
aspnet_regiis -pef appSettings D:\code\Github\Repos\CryptoConnStrDemo\CryptoConnStrDemo

# 同上,參數改為 pdf 則為解密
aspnet_regiis -pdf appSettings D:\code\Github\Repos\CryptoConnStrDemo\CryptoConnStrDemo

如果要在本機測試的話,需要先將 Visual Studio 在建置的時候使用 local 的 IIS,而非 IISExpress

如果需要將本機的 RSA 金鑰容器給別台主機使用,則需要先將金鑰容器匯出,再由別的主機匯入使用

1
2
3
4
# 匯出
aspnet_regiis -px "NetFrameworkConfigurationKey" D:/RSAkeys.xml -pri
# 匯入
aspnet_regiis -pi "NetFrameworkConfigurationKey" D:/RSAkeys.xml

參考資料

  1. 配置檔案(Web.Config)加密解密詳細說明
  2. Day15 資料使用安全(保護連接字串)下
  3. ASP.NET 使用相同 RSA 金鑰容器幫 web.config 連線字串加密