首页 文章

安全存储数据库密码

提问于
浏览
1

我想在创建SQL Server CE数据库时随机生成加密密钥和密码,然后以某种安全的方式保存密钥,以允许程序打开连接,但潜在的攻击者无法轻易访问 .

我正在开发一个离线WPF应用程序,它将某些用户和设置信息存储在本地数据库中 .

我目前的实现是拥有一个用户设置的“设备密码”,它用作生成的SQL Server CE数据库密码的加密密钥 . 然后将base64加密数据库密码保存在简单的.txt设置文件中 . 当应用程序启动时,用户输入设备密码,该字符串将用作保存密码的解密密钥 . 如果生成的字符串能够打开与数据库的连接,则密码正确并且程序以完全访问权限打开 .

我现在要做的是修改系统以允许具有特定用户名/密码凭据的多个用户打开程序并使用不同级别的权限访问数据库 . 我试图实现这一点的方法是单独处理用户身份验证,并打开数据库而不管加载一些基本应用程序信息的凭据 .

以下是我目前的实施情况:

var candidateDBPwd = DecryptDatabasePassword(passwordBox.Password, Settings.Instance.EncryptedDatabasePassword);

        if (candidateDBPwd.IsNullOrEmpty())
        {
            // User's password didn't decrypt database password.
            return false;
        }

        if (File.Exists(Constants.DB_FILE))
        {
            // Normal operation: Try to open the database file to see that 
            // we've got the correct password.
            string databaseArguments = Constants.DB_ARGS_SECURE + candidateDBPwd;
            using (var conn = new SqlCeConnection(databaseArguments))
            {
                try
                {
                    conn.Open();
                }
                catch (System.Data.SqlServerCe.SqlCeException ex)
                {
                    // Failed to open the database: User's password must have been wrong!
                    return false;
                }
            }

我花了几个小时来研究类似的问题,现在我开始怀疑它是否可能 . 共识似乎表明在App.config文件中存储密码或connectionStrings是徒劳的,因为如果加密这些部分,您仍然需要将该密钥存储在代码中的某个位置 . 关于这个问题的大多数现有SO线程似乎已经过时了几年,而且这种做法似乎已被弃用 . 是否有一些新的可敬的方式来存储本地数据库密码?或者您会推荐一种不同的方法来实现该功能吗?

2 回答

  • 1

    您可以将其存储在注册表编辑器中 . 你提到你的系统离线wpf应用程序 .

  • -1

    对于您的信息,这里是可用于加密 app.config 的某些部分的代码段 . 这是机器特定的加密,我认为这是最简单直接的方法 .

    我在Click-once应用程序中使用它,以便在首次启动应用程序时对配置部分进行加密 . 这意味着,它在发布服务器上未加密,它也是未加密的下载,并在安装完成并启动应用程序后立即加密 .

    因此,使用此方法,您必须以未加密的方式分发文件,并且只有在安装完成后才会对它们进行加密 . 我想这可以通过在安装期间运行此代码来实现,这取决于您计划如何安装应用程序 .

    您也可以使用 UnprotectSection() 来解密以前加密的部分 .

    static void EncryptConfig()
    {
        // Encrypt config for ClickOnce deploys on first run
        // ClickOnce deploys config into 2 dirs, so the parent dir is traversed to encrypt all
        if (ApplicationDeployment.IsNetworkDeployed)
        {
            // Get paths
            Assembly asm = Assembly.GetExecutingAssembly();
            string exeName = Path.GetFileName(asm.Location);
            string configName = exeName + ".config";
            DirectoryInfo parentPath = Directory.GetParent(Directory.GetCurrentDirectory());
    
            // Protect config files
            foreach (DirectoryInfo dir in parentPath.GetDirectories())
            {
                foreach (FileInfo fil in dir.GetFiles())
                {
                    if (fil.Name == configName)
                    {
                        ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap();
                        fileMap.ExeConfigFilename = fil.FullName;
                        Configuration config = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
                        ProtectSection(config, "connectionStrings");
                        config.Save(ConfigurationSaveMode.Modified);
                    }
                }
            }
        }
    }
    private static void ProtectSection(Configuration config, string sectionName)
    {
        ConfigurationSection section = config.GetSection(sectionName);
        if (section != null)
        {
            if (!section.SectionInformation.IsProtected)
            {
                section.SectionInformation.ProtectSection("DataProtectionConfigurationProvider");
            }
            section.SectionInformation.ForceSave = true;
        }
        else
            Tools.LogWarning("Section {1} not found in {0}.",config.FilePath, sectionName);
    }
    

相关问题