應用程序配置文件(App.config/Web.config)中的 connectionStrings 節點包含數據庫訪問敏感信息(服務器地址、賬號、密碼)。以明文存儲存在極大安全風險,生產環境務必加密保護。
.NET Framework 提供 ConfigurationSection.SectionInformation.ProtectSection 方法,基於機器級或用戶級 DPAPI(Data Protection API)實現配置節點加密,無需管理金鑰,部署簡便。
using System.Configuration;
public static class ConnectionStringEncryptor
{
///
/// 加密或解密 connectionStrings 節點
///
/// true=加密,false=解密
/// 加密提供者,默認 DataProtectionConfigurationProvider (DPAPI 機器級)
/// 可選:指定配置文件路徑,默認當前執行程序配置
public static void ToggleEncryption(bool encrypt, string provider = "DataProtectionConfigurationProvider", string exeConfigPath = null)
{
Configuration config;
if (string.IsNullOrEmpty(exeConfigPath))
config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
else
config = ConfigurationManager.OpenExeConfiguration(exeConfigPath);
var section = config.GetSection("connectionStrings") as ConnectionStringsSection;
if (section == null)
throw new InvalidOperationException("未找到 connectionStrings 節點");
// 檢查節點是否被鎖定
if (section.ElementInformation.IsLocked || section.SectionInformation.IsLocked)
throw new InvalidOperationException("connectionStrings 節點被鎖定,無法修改保護狀態");
try
{
if (encrypt && !section.SectionInformation.IsProtected)
{
// 加密:使用指定提供者
section.SectionInformation.ProtectSection(provider);
Console.WriteLine($"[加密成功] 已使用 {provider} 加密 connectionStrings");
}
else if (!encrypt && section.SectionInformation.IsProtected)
{
// 解密
section.SectionInformation.UnprotectSection();
Console.WriteLine("[解密成功] connectionStrings 已恢復明文");
}
else
{
Console.WriteLine($"[無需操作] 當前狀態:{(section.SectionInformation.IsProtected ? "已加密" : "明文")},目標:{(encrypt ? "加密" : "解密")}");
return;
}
// 強制保存並刷新
section.SectionInformation.ForceSave = true;
config.Save(ConfigurationSaveMode.Modified);
ConfigurationManager.RefreshSection("connectionStrings");
}
catch (ConfigurationErrorsException ex)
{
throw new InvalidOperationException("配置文件保存失敗,請檢查權限或文件是否被佔用", ex);
}
}
}
| 提供者名稱 | 加密範圍 | 適用場景 | 備註 |
|---|---|---|---|
DataProtectionConfigurationProvider (DPAPI 機器級) |
機器級 | 單台服務器部署、Web 伺服器場 (需同步金鑰) | 默認推薦,性能好 |
DataProtectionConfigurationProvider (DPAPI 用戶級) |
用戶級 | 特定服務賬號運行的應用 | 需指定 useMachineProtection="false" |
RsaProtectedConfigurationProvider |
可導出金鑰跨機器 | Web 伺服器場、容器化部署、需備份金鑰 | 需預先創建/導入 RSA 金鑰容器 |
無需寫代碼,直接使用 .NET 內置工具:
REM 加密 Web.config (ASP.NET 應用)
aspnet_regiis.exe -pef "connectionStrings" "C:\Path\To\WebApp" -prov "DataProtectionConfigurationProvider"
REM 加密 App.config (WinForm/WPF/Console,需重命名為 web.config 暫時處理)
REM 或使用自定義工具調用上述 ToggleEncryption 方法
REM 解密
aspnet_regiis.exe -pdf "connectionStrings" "C:\Path\To\WebApp"
aspnet_regiis -pc "MyKeys" -expaspnet_regiis -px "MyKeys" "C:\keys.xml" -priaspnet_regiis -pi "MyKeys" "C:\keys.xml"aspnet_regiis -pa "MyKeys" "IIS APPPOOL\MyAppPool"加密後的 connectionStrings 將呈現如下形式:
<connectionStrings configProtectionProvider="DataProtectionConfigurationProvider">
<EncryptedData>
<CipherData><CipherValue>AQAAANCMnd8BFdERjHoAwE/Cl+sBAAA...</CipherValue></CipherData>
</EncryptedData>
</connectionStrings>
應用程序運行時自動解密,代碼讀取方式完全不變:
var connStr = ConfigurationManager.ConnectionStrings["MyDb"].ConnectionString; // 自動獲取解密後明文
ConfigurationErrorsException,需記錄日誌並告警利用 .NET 內置 ProtectSection 機制配合 DPAPI/RSA 提供者,可零依賴實現連接字符串生產級加密。核心優勢:無需管理金鑰、代碼零改動、運行時自動解密、支持集群部署。建議結合 CI/CD 流水線在部署階段自動化執行加密,構建「配置文件不落地明文」的安全體系。