.NET Core 数据库连接字符串加密与解密

.NET Core 数据库连接字符串加密与解密

每次把数据库密码直接写在配置文件里,我都感觉像是在大街上裸奔------虽然大家都这么做,但总觉得哪里不对劲。

想想看,我们把最重要的数据库密码,就这么明晃晃地写在appsettings.json里。万一哪天配置文件不小心泄露了,黑客们简直就像拿到了金库钥匙,我们的数据就全暴露了!

别担心,给数据库密码"穿衣服"没你想的那么难。今天我要分享的就是一个超级实用的方法:

用个神奇的小工具把密码加密

把加密后的乱码存到配置文件里

程序运行时再自动解密使用

这样就算有人看到你的配置文件,也只是一堆看不懂的乱码,再也不用担心密码泄露了!

这里使用的是AES加密算法

AES(高级加密标准)是一种对称加密算法,使用128/192/256位密钥对128位数据块进行加密,通过多轮替换、移位和混淆操作确保安全性,广泛应用于网络通信、文件加密等领域。

一、实战:控制台加密解密工具开发

1. 基本功能实现

这里推荐使用控制台程序来将字符串加密,首先创建一个控制台程序。EncryptConnectStrings,然后再默认的Program.cs文件中创建两个方法EncryptConnectionStringDecryptConnectionString分别负责加密和解密.

然后还需要增加一个变量用于保存秘钥

csharp 复制代码
public static string encryptionKey = "EncryptionKey";

加密

接下来就是加密的方法EncryptConnectionString

csharp 复制代码
 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

csharp 复制代码
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方法中修改:

csharp 复制代码
    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用于询问是否继续

csharp 复制代码
    static bool AskToContinue()
    {
        Console.Write("\n是否继续其他操作?(Y/N): ");
        var response = Console.ReadLine()?.Trim().ToUpper();
        return response == "Y";
    }

增加一个方法用于将加密与解密的内容保存到文件中去,防止丢失

csharp 复制代码
  static void SaveToFile(string content, string fileName)
  {
      try
      {
          File.WriteAllText(fileName, content);
          Console.WriteLine($"结果已保存到: {Path.GetFullPath(fileName)}");
      }
      catch (Exception ex)
      {
          Console.WriteLine($"保存文件失败: {ex.Message}");
      }
  }

然后是加密解密的方法

csharp 复制代码
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());
}

选择加密或者解密后运行的方法:

csharp 复制代码
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}");
    }
}

获取秘钥的方法,如果需要手动输入秘钥则取消下面的注释即可.

csharp 复制代码
    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. 整个源码:

csharp 复制代码
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());
    }
}
相关推荐
2501_915374351 小时前
Neo4j 图数据库安装教程(2024最新版)—— Windows / Linux / macOS 全平台指南
数据库·windows·neo4j
it-搬运工1 小时前
3.图数据Neo4j - CQL的使用
数据库·neo4j
-借我杀死庸碌的情怀-2 小时前
navicat可视化页面直接修改数据库密码——mysql、postgresql、mangodb等
数据库·mysql·postgresql
码码不爱我3 小时前
学习笔记:Redis入门
数据库·redis·学习
熊出没3 小时前
阿里云云原生数据库PolarDB和普通云数据库的区别?
数据库·阿里云·云原生
zhuiQiuMX4 小时前
SQL力扣
数据库·sql·leetcode
debug 小菜鸟4 小时前
MySQL 主从复制与一主多从架构实战详解
数据库·mysql·架构
远方16094 小时前
29-Oracle 23ai Flashback Log Placement(闪回日志灵活配置)
数据库·sql·oracle·database
꧁༺摩༒西༻꧂4 小时前
Windows安装Oracle19
数据库·oracle
代码老y4 小时前
前端开发中的可访问性设计:让互联网更包容
java·服务器·前端·数据库