.NET Core 数据库连接字符串加密与解密
每次把数据库密码直接写在配置文件里,我都感觉像是在大街上裸奔——虽然大家都这么做,但总觉得哪里不对劲。
想想看,我们把最重要的数据库密码,就这么明晃晃地写在appsettings.json里。万一哪天配置文件不小心泄露了,黑客们简直就像拿到了金库钥匙,我们的数据就全暴露了!
别担心,给数据库密码"穿衣服"没你想的那么难。今天我要分享的就是一个超级实用的方法:
用个神奇的小工具把密码加密
把加密后的乱码存到配置文件里
程序运行时再自动解密使用
这样就算有人看到你的配置文件,也只是一堆看不懂的乱码,再也不用担心密码泄露了!
这里使用的是AES加密算法
AES(高级加密标准)是一种对称加密算法,使用128/192/256位密钥对128位数据块进行加密,通过多轮替换、移位和混淆操作确保安全性,广泛应用于网络通信、文件加密等领域。
一、实战:控制台加密解密工具开发
1. 基本功能实现
这里推荐使用控制台程序来将字符串加密,首先创建一个控制台程序。EncryptConnectStrings
,然后再默认的Program.cs
文件中创建两个方法EncryptConnectionString
、DecryptConnectionString
分别负责加密和解密.
然后还需要增加一个变量用于保存秘钥
public static string encryptionKey = "EncryptionKey";
加密
接下来就是加密的方法EncryptConnectionString
static void EncryptConnectionString(string encryptionKey)
{
var connectionString = "Server=myServer;Database=myDB;User=myUser;Password=myPass;";
try
{
if (string.IsNullOrEmpty(connectionString )){
Console.WriteLine("\n加密字符串为空!");
return;
}
using var aes = Aes.Create();
var pdb = new Rfc2898DeriveBytes(encryptionKey,
new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
aes.Key = pdb.GetBytes(32);
aes.IV = pdb.GetBytes(16);
using var memoryStream = new MemoryStream();
using (var cryptoStream = new CryptoStream(memoryStream, aes.CreateEncryptor(), CryptoStreamMode.Write))
{
byte[] plainBytes = Encoding.UTF8.GetBytes(connectionString );
cryptoStream.Write(plainBytes, 0, plainBytes.Length);
}
string encrypted = Convert.ToBase64String(memoryStream.ToArray());
Console.WriteLine("\n加密成功!");
Console.WriteLine("加密后的结果:");
Console.WriteLine(encrypted);
// 生成可直接粘贴到appsettings.json的内容
Console.WriteLine("\nappsettings.json 配置片段:");
Console.WriteLine($"\"ConnectionStrings\": {{\n \"YourConnection\": \"{encrypted}\"\n}}");
}
catch (Exception ex)
{
Console.WriteLine($"加密失败: {ex.Message}");
}
}
这里生成的字符串可以直接复制到.Net Core项目使用,.Net Core项目的配置在后面介绍
解密
解密方法为DecryptConnectionString
static void DecryptConnectionString(string encryptionKey)
{
var encryptedString = "wzeN1u22aXwFr47U7PVzUEnk5rVdkBcGYLNABI01zDKSyQ2QjQPmPvJFdDDa940CUi+k79nkwCv/jtWFUIj+Dw==";
if (string.IsNullOrEmpty(encryptedString))
{
Console.WriteLine("错误:加密字符串不能为空");
return;
}
try
{
using var aes = Aes.Create();
var pdb = new Rfc2898DeriveBytes(encryptionKey,
new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
aes.Key = pdb.GetBytes(32);
aes.IV = pdb.GetBytes(16);
var cipherBytes = Convert.FromBase64String(encryptedString);
using var memoryStream = new MemoryStream();
using (var cryptoStream = new CryptoStream(memoryStream, aes.CreateDecryptor(), CryptoStreamMode.Write))
{
cryptoStream.Write(cipherBytes, 0, cipherBytes.Length);
}
string decrypted = Encoding.UTF8.GetString(memoryStream.ToArray());
Console.WriteLine("\n解密成功!");
Console.WriteLine("原始连接字符串:");
Console.WriteLine(decrypted);
}
catch (Exception ex)
{
Console.WriteLine($"解密失败: {ex.Message}");
}
}
可以看到解密后的字符串和加密之前一样,那就对了
2. 动态输入秘钥与需要加密的内容
上面实现了基本功能,但是如果批量加密的时候每次都要重启一下程序,很麻烦,所以这里修改为动态输入秘钥与字符串(也可以固定死秘钥).
在main方法中修改:
static void Main(string[] args)
{
Console.WriteLine("数据库连接字符串加密/解密工具");
Console.WriteLine("=============================");
// 1. 获取加密密钥
string encryptionKey = GetEncryptionKey();
bool continueRunning = true;
while (continueRunning)
{
// 2. 选择操作模式
Console.WriteLine("\n[选择操作]");
Console.WriteLine("1. 加密连接字符串");
Console.WriteLine("2. 解密连接字符串");
Console.Write("请选择(1/2): ");
var choice = Console.ReadLine();
switch (choice)
{
case "1":
EncryptConnectionString(encryptionKey);
break;
case "2":
DecryptConnectionString(encryptionKey);
break;
default:
Console.WriteLine("无效选择,请重新输入");
break;
}
// 3. 询问用户是否继续
continueRunning = AskToContinue();
}
Console.WriteLine("\n程序结束,按任意键退出...");
Console.ReadKey();
}
增加方法AskToContinue
用于询问是否继续
static bool AskToContinue()
{
Console.Write("\n是否继续其他操作?(Y/N): ");
var response = Console.ReadLine()?.Trim().ToUpper();
return response == "Y";
}
增加一个方法用于将加密与解密的内容保存到文件中去,防止丢失
static void SaveToFile(string content, string fileName)
{
try
{
File.WriteAllText(fileName, content);
Console.WriteLine($"结果已保存到: {Path.GetFullPath(fileName)}");
}
catch (Exception ex)
{
Console.WriteLine($"保存文件失败: {ex.Message}");
}
}
然后是加密解密的方法
static string Encrypt(string plainText, string encryptionKey)
{
if (string.IsNullOrEmpty(plainText)) return plainText;
using var aes = Aes.Create();
var pdb = new Rfc2898DeriveBytes(encryptionKey,
new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
aes.Key = pdb.GetBytes(32);
aes.IV = pdb.GetBytes(16);
using var memoryStream = new MemoryStream();
using (var cryptoStream = new CryptoStream(memoryStream, aes.CreateEncryptor(), CryptoStreamMode.Write))
{
byte[] plainBytes = Encoding.UTF8.GetBytes(plainText);
cryptoStream.Write(plainBytes, 0, plainBytes.Length);
}
return Convert.ToBase64String(memoryStream.ToArray());
}
static string Decrypt(string cipherText, string encryptionKey)
{
if (string.IsNullOrEmpty(cipherText)) return cipherText;
using var aes = Aes.Create();
var pdb = new Rfc2898DeriveBytes(encryptionKey,
new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
aes.Key = pdb.GetBytes(32);
aes.IV = pdb.GetBytes(16);
var cipherBytes = Convert.FromBase64String(cipherText);
using var memoryStream = new MemoryStream();
using (var cryptoStream = new CryptoStream(memoryStream, aes.CreateDecryptor(), CryptoStreamMode.Write))
{
cryptoStream.Write(cipherBytes, 0, cipherBytes.Length);
}
return Encoding.UTF8.GetString(memoryStream.ToArray());
}
选择加密或者解密后运行的方法:
static void EncryptConnectionString(string encryptionKey)
{
Console.WriteLine("\n[加密模式]");
Console.Write("请输入要加密的连接字符串: ");
var connectionString = Console.ReadLine();
if (string.IsNullOrEmpty(connectionString))
{
Console.WriteLine("错误:连接字符串不能为空");
return;
}
try
{
string encrypted = Encrypt(connectionString, encryptionKey);
Console.WriteLine("\n加密成功!");
Console.WriteLine("加密后的结果:");
Console.WriteLine(encrypted);
// 生成可直接粘贴到appsettings.json的内容
Console.WriteLine("\nappsettings.json 配置片段:");
Console.WriteLine($"\"ConnectionStrings\": {{\n \"YourConnection\": \"{encrypted}\"\n}}");
// 保存到文件
SaveToFile(encrypted, "encrypted_connection.txt");
}
catch (Exception ex)
{
Console.WriteLine($"加密失败: {ex.Message}");
}
}
static void DecryptConnectionString(string encryptionKey)
{
Console.WriteLine("\n[解密模式]");
Console.Write("请输入要解密的连接字符串: ");
var encryptedString = Console.ReadLine();
if (string.IsNullOrEmpty(encryptedString))
{
Console.WriteLine("错误:加密字符串不能为空");
return;
}
try
{
string decrypted = Decrypt(encryptedString, encryptionKey);
Console.WriteLine("\n解密成功!");
Console.WriteLine("原始连接字符串:");
Console.WriteLine(decrypted);
// 保存到文件
SaveToFile(decrypted, "decrypted_connection.txt");
}
catch (Exception ex)
{
Console.WriteLine($"解密失败: {ex.Message}");
}
}
获取秘钥的方法,如果需要手动输入秘钥则取消下面的注释即可.
static string GetEncryptionKey()
{
return "MyAppSecureKey";
//Console.Write("\n请输入加密密钥(至少16个字符): ");
//var key = Console.ReadLine();
//if (string.IsNullOrEmpty(key) || key.Length < 16)
//{
// Console.WriteLine("错误:密钥必须至少16个字符");
// return GetEncryptionKey(); // 递归调用直到获取有效密钥
//}
//return key;
}
3. 整个源码:
using System;
using System.Security.Cryptography;
using System.Text;
using System.IO;
using EncryptConnectStrings;
class Program
{
static void Main(string[] args)
{
Console.WriteLine("数据库连接字符串加密/解密工具");
Console.WriteLine("=============================");
// 1. 获取加密密钥
string encryptionKey = GetEncryptionKey();
bool continueRunning = true;
while (continueRunning)
{
// 2. 选择操作模式
Console.WriteLine("\n[选择操作]");
Console.WriteLine("1. 加密连接字符串");
Console.WriteLine("2. 解密连接字符串");
Console.Write("请选择(1/2): ");
var choice = Console.ReadLine();
switch (choice)
{
case "1":
EncryptConnectionString(encryptionKey);
break;
case "2":
DecryptConnectionString(encryptionKey);
break;
default:
Console.WriteLine("无效选择,请重新输入");
break;
}
// 3. 询问用户是否继续
continueRunning = AskToContinue();
}
Console.WriteLine("\n程序结束,按任意键退出...");
Console.ReadKey();
}
static string GetEncryptionKey()
{
return "MyAppSecureKey123!@#";
//Console.Write("\n请输入加密密钥(至少16个字符): ");
//var key = Console.ReadLine();
//if (string.IsNullOrEmpty(key) || key.Length < 16)
//{
// Console.WriteLine("错误:密钥必须至少16个字符");
// return GetEncryptionKey(); // 递归调用直到获取有效密钥
//}
//return key;
}
static void EncryptConnectionString(string encryptionKey)
{
Console.WriteLine("\n[加密模式]");
Console.Write("请输入要加密的连接字符串: ");
var connectionString = Console.ReadLine();
if (string.IsNullOrEmpty(connectionString))
{
Console.WriteLine("错误:连接字符串不能为空");
return;
}
try
{
string encrypted = Encrypt(connectionString, encryptionKey);
Console.WriteLine("\n加密成功!");
Console.WriteLine("加密后的结果:");
Console.WriteLine(encrypted);
// 生成可直接粘贴到appsettings.json的内容
Console.WriteLine("\nappsettings.json 配置片段:");
Console.WriteLine($"\"ConnectionStrings\": {{\n \"YourConnection\": \"{encrypted}\"\n}}");
// 保存到文件
SaveToFile(encrypted, "encrypted_connection.txt");
}
catch (Exception ex)
{
Console.WriteLine($"加密失败: {ex.Message}");
}
}
static void DecryptConnectionString(string encryptionKey)
{
Console.WriteLine("\n[解密模式]");
Console.Write("请输入要解密的连接字符串: ");
var encryptedString = Console.ReadLine();
if (string.IsNullOrEmpty(encryptedString))
{
Console.WriteLine("错误:加密字符串不能为空");
return;
}
try
{
string decrypted = Decrypt(encryptedString, encryptionKey);
Console.WriteLine("\n解密成功!");
Console.WriteLine("原始连接字符串:");
Console.WriteLine(decrypted);
// 保存到文件
SaveToFile(decrypted, "decrypted_connection.txt");
}
catch (Exception ex)
{
Console.WriteLine($"解密失败: {ex.Message}");
}
}
static bool AskToContinue()
{
Console.Write("\n是否继续其他操作?(Y/N): ");
var response = Console.ReadLine()?.Trim().ToUpper();
return response == "Y";
}
static void SaveToFile(string content, string fileName)
{
try
{
File.WriteAllText(fileName, content);
Console.WriteLine($"结果已保存到: {Path.GetFullPath(fileName)}");
}
catch (Exception ex)
{
Console.WriteLine($"保存文件失败: {ex.Message}");
}
}
static string Encrypt(string plainText, string encryptionKey)
{
if (string.IsNullOrEmpty(plainText)) return plainText;
using var aes = Aes.Create();
var pdb = new Rfc2898DeriveBytes(encryptionKey,
new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
aes.Key = pdb.GetBytes(32);
aes.IV = pdb.GetBytes(16);
using var memoryStream = new MemoryStream();
using (var cryptoStream = new CryptoStream(memoryStream, aes.CreateEncryptor(), CryptoStreamMode.Write))
{
byte[] plainBytes = Encoding.UTF8.GetBytes(plainText);
cryptoStream.Write(plainBytes, 0, plainBytes.Length);
}
return Convert.ToBase64String(memoryStream.ToArray());
}
static string Decrypt(string cipherText, string encryptionKey)
{
if (string.IsNullOrEmpty(cipherText)) return cipherText;
using var aes = Aes.Create();
var pdb = new Rfc2898DeriveBytes(encryptionKey,
new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
aes.Key = pdb.GetBytes(32);
aes.IV = pdb.GetBytes(16);
var cipherBytes = Convert.FromBase64String(cipherText);
using var memoryStream = new MemoryStream();
using (var cryptoStream = new CryptoStream(memoryStream, aes.CreateDecryptor(), CryptoStreamMode.Write))
{
cryptoStream.Write(cipherBytes, 0, cipherBytes.Length);
}
return Encoding.UTF8.GetString(memoryStream.ToArray());
}
}