在 clickonce 应用程序中安全地存储服务帐户凭据

2023-12-13

我正在编写一个 ClickOnce 应用程序,该应用程序使用服务帐户凭据运行批处理文件进程。我需要存储服务帐户凭据,以便程序可以在运行进程之前将用户名/密码添加到 process.startinfo 属性。用户不知道该密码,因此不会提示他们输入密码。我相信这意味着我无法以这种方式存储哈希并验证密码,我生成的哈希值必须是可逆的,以便它可以将正确的密码添加到 startinfo 属性。我在这个网站上进行了搜索,并提出了一个可行的弗兰肯斯坦式解决方案,但它不是很安全。目前,我使用此方法对密码进行加密,存储加密值,然后在运行时使用解密方法获取密码(加密方法在运行时从未运行,我在调试期间在 Visual Studio 中运行它,复制了值,然后在下面的解密方法中使用该值):

// used to generate decrypted acct creds
    private void EncryptText(string plaintext)
    {
        string outsrt = null;
        RijndaelManaged aesAlg = null;

        try
        {
            // generate key from secret and salt
            Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(sharedsecret, _salt);

            aesAlg = new RijndaelManaged();
            aesAlg.Key = key.GetBytes(aesAlg.KeySize / 8);

            ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);

            using (MemoryStream mEncrypt = new MemoryStream())
            {
                // prepend the IV
                mEncrypt.Write(BitConverter.GetBytes(aesAlg.IV.Length), 0, sizeof(int));
                mEncrypt.Write(aesAlg.IV, 0, aesAlg.IV.Length);
                using (CryptoStream csEncrypt = new CryptoStream(mEncrypt, encryptor, CryptoStreamMode.Write))
                {
                    using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
                    {
                        // write all data to the stream
                        swEncrypt.Write(plaintext);
                    }
                }

                outsrt = Convert.ToBase64String(mEncrypt.ToArray());
            }
        }
        finally
        {
            if (aesAlg != null)
                aesAlg.Clear();
        }

        Console.WriteLine(outsrt);
    }

解密方法如下:

private string GetServiceAcctPW()
    {

        // Declare the RijndaelManaged object
        // used to decrypt the data.
        RijndaelManaged aesAlg = null;

        // Declare the string used to hold
        // the decrypted text.
        string plaintext = null;

        try
        {
            // generate the key from the shared secret and the salt
            Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(sharedsecret, _salt);

            // Create the streams used for decryption.                
            byte[] bytes = Convert.FromBase64String("EncryptedValueHere");
            using (MemoryStream msDecrypt = new MemoryStream(bytes))
            {
                // Create a RijndaelManaged object
                // with the specified key and IV.
                aesAlg = new RijndaelManaged();
                aesAlg.Key = key.GetBytes(aesAlg.KeySize / 8);
                // Get the initialization vector from the encrypted stream
                aesAlg.IV = ReadByteArray(msDecrypt);
                // Create a decrytor to perform the stream transform.
                ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
                using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
                {
                    using (StreamReader srDecrypt = new StreamReader(csDecrypt))

                        // Read the decrypted bytes from the decrypting stream
                        // and place them in a string.
                        plaintext = srDecrypt.ReadToEnd();
                }
            }
        }
        catch(Exception e)
        {
            Console.WriteLine("Error decrypting password");
            Console.WriteLine(e.StackTrace);
            logger.WriteToLog(Logger.LogCodes.ERROR, "Error decrypting service account password");
            MessageBox.Show("An error occurred while trying to start the installation process\nPlease contact the Service Desk for further assistance");
        }
        finally
        {
            // Clear the RijndaelManaged object.
            if (aesAlg != null)
                aesAlg.Clear();
        }

        return plaintext;
    }

这段代码工作得很好,但是,我知道它不安全。我的代码审查人员说他能够在一个小时内用 dotPeek 破解它,因为它只是添加了一层混淆。在应用程序中存储这些凭据的最佳/正确方法是什么?


加密密钥位于专用服务器上。

密码与要加密的 id 一起发送到服务器,并返回加密后的密码以供数据库存储。

当需要密码时,会使用 ID 向专用服务器发出请求,并返回解密后的密码。

密码永远不会保存到磁盘上,并且密钥永远不会在专用服务器上可用。

专用服务器有点像穷人的 HSM。

这是加密,而不是散列。加密密钥与随机 IV 一起是秘密的,该 IV 与 ID 一起保存在专用服务器上。密钥不可用并且与密码无关,因此没有比暴力破解加密密钥更好的攻击了,加密密钥本质上太大而无法被暴力破解。

服务器需要非常安全,只有几次双因素登录,并且不能访问互联网。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 clickonce 应用程序中安全地存储服务帐户凭据 的相关文章

随机推荐

  • 如何检测对 HTML5“下载”属性的支持?

    HTML5 中实现的新功能之一是download锚标记的属性 此属性的好处是 它为用户提供了下载在客户端应用程序中创建的内容的方法 例如图像 例如从画布转换而来 目前 对此功能的支持很差 所以我想知道如何检测浏览器中对此功能的支持 Use
  • Knockout JS“uniqueName”绑定 - 两个字段同名

    我正在使用 Knockout JS 创建一个编辑器 我正在使用 foreach 属性循环模型中的列表 tbody 我正在使用 JQuery 不显眼的验证 它需要一个 name 属性来验证 我想为两个字段分配相同的名称 以便能够输出验证消息
  • 在 C# 中执行 SQL 语句?

    大家好 我想执行我的 SQL 语句 但我遇到语法问题 有人可以帮助我理解我做错了什么吗 谢谢 阿什 public void AddToDatabase string WordArray int Good int Bad int Remove
  • 如何在 IIS 上使用 django 获取静态 CSS 文件?

    我在 IIS8 上安装了 django 现在我想将其配置为提供静态文件 我一直在关注本教程 我已将其添加到设置 py STATIC URL 静态 STATIC ROOT C my django project NZtracker stati
  • UIScrollView 内的 UIDatePicker 与页面

    我有一个包含 2 个页面的 UIScrollView 我可以在它们之间水平滚动 但是 在我的其中一个页面上 我有一个 UIDatePicker 并且滚动视图正在拦截垂直触摸事件 因此我无法再操作日期选择器 除非通过单击或点击 有没有办法告诉
  • 如何在 Mac 上使用 Visual Studio Code 将 Azure 发布设置文件导入到 Angular 项目?

    我已经使用 Visual Studio Code 构建了一个 Angular 应用程序 并被指示使用提供的 publishsettings 文件将其部署到 Azure 我实现这一目标的尝试失败了 除了 publishsettings 文件和
  • PHP - 无法访问外部 URL

    由于流量很大 我最近升级了网站的服务器 在新服务器上 PHP 的某些方面似乎被破坏了 我有一个非常具体的代码 但不起作用 但是 由于版权原因 我只能向您展示非机密的等效内容 这段代码有效绝对完美在升级之前 现在这里或那里的一些奇怪的设置阻止
  • 如何在 C# 中将图像覆盖或叠加到视频上

    我试图弄清楚如何在 Visual C 中将图像覆盖在 保存的文件 视频上 然后重新保存它 在过去的四个小时里 我一直在努力做到这一点 到处寻找 所以任何帮助将不胜感激 DirectShow NET 是 DirectShow 的包装器 Dir
  • UIViewController 自由格式尺寸问题

    我正在使用这个神奇的 PopupViewController https github com martinjuhasz MJPopupViewController 控制 我的应用程序使用故事板 我已经按照开发人员的指示创建了一个自定义 S
  • 提取双引号之间的字符串

    我正在阅读来自期刊或论文来源的响应 并且我将 html 响应作为字符串 如下所示 一些人认为 梦表达了 人格的深刻方面 Foulkes 184 尽管其他人不同意 我的目标只是从给定字符串中提取所有引号并将它们保存到一个列表中 我的方法是 m
  • 如何使用JAVA向COM PORT发送数据? [复制]

    这个问题在这里已经有答案了 可能的重复 Windows 上的 Java 串行通信 朋友们 我想在JAVA中连接并传输数据到COM PORT 虚拟的或原始的 这个问题已经被问过并回答过很多次了 使用Java从串口读取文件 Java读取串口 J
  • 如何编译Boost多线程程序?

    我安装了boost库 没有多线程 一切都很顺利 我如何编译这个测试程序 include
  • iOS 应用程序在 PushViewController 上冻结

    我的导航控制器在按下时会间歇性冻结 它似乎将新的视图控制器添加到堆栈中 但动画从未发生 我还有另外两个容器 它们在屏幕上保存视图控制器 并且在导航控制器冻结后我可以与它们进行良好的交互 真正有趣的是 如果我尝试将另一个视图控制器推送到导航控
  • Python 最小值/最大值的关键字函数

    我试图理解这是如何工作的 my dict a 2 b 1 min my dict key my dict get produces b 这是一项非常酷的功能 我想更好地了解它 基于文档 分钟 可迭代 键 返回可迭代中的最小项或两个或多个参数
  • c# - DbContext 在BackgroundService 中释放

    我有一个 WebAPI 它也应该从 RabbitMQ 接收消息 我用了this教程 因为我知道有时 IIS 喜欢终止长时间运行的任务 但尚未在服务器上测试它 也许它不起作用 我有一个处理通过 RabbitMQ 接收的消息的服务 我遇到的第一
  • 让数据绑定 WPF Listbox 生成子类 ListboxItems

    我想让我的 WPF Listbox 数据绑定 生成子类 ListboxItems 而不是常规 ListboxItems 在这种情况下 DataTemplate 是不够的 因为我需要子类 ListBoxItems 的一些自定义属性 有没有办法
  • Android - 如何禁用长按搜索按钮 (Nexus One)

    Android文档描述了如何禁用Activity中的搜索功能 公共布尔 onSearchRequested 返回假 短按 Nexus One 上的搜索按钮即可正常工作 但是 它不会禁用长按 仍然会启动语音搜索 如何禁用长按语音搜索 谢谢 我
  • 当所需DLL的名称可能发生变化时,如何在运行时选择DllImport的路径?

    我今天问了这个问题 但它被错误地关闭了 我无法选择重新打开它 因此 我不得不再问一遍 我有一个类 其中有一长串定义 如下所示 DllImport NativeLibraryName EntryPoint FunctionName Calli
  • Python 正则表达式 OR

    假设我想要一个同时匹配 从我的 iPhone 发送 和 从我的 iPod 发送 的正则表达式 我该如何写这样的表达式 我尝试过类似的事情 re compile Sent from my iPhone iPod 但似乎不起作用 re comp
  • 在 clickonce 应用程序中安全地存储服务帐户凭据

    我正在编写一个 ClickOnce 应用程序 该应用程序使用服务帐户凭据运行批处理文件进程 我需要存储服务帐户凭据 以便程序可以在运行进程之前将用户名 密码添加到 process startinfo 属性 用户不知道该密码 因此不会提示他们