【问题标题】:SecureString for storing in memory and presenting passwords? Or something else?SecureString 用于存储在内存中并显示密码?或者是其他东西?
【发布时间】:2011-06-26 11:51:19
【问题描述】:

我一直在使用 C# 为自己编写一个小程序,我可以使用它来存储我的密码,然后检索它们以进行查看/编辑。

虽然密码以加密格式存储到磁盘中,但当它们被读入内存以在表单上显示/编辑时,它们是未加密的。

我了解到内存中存在未加密的密码是一个相当大的安全问题,所以我遇到了SecureString 类。

是否有比使用SecureString 类更安全的方法来执行此操作,或者SecureString 是否名副其实?

【问题讨论】:

  • 从不存储密码,甚至不加密。只存储他们的哈希值。
  • @HansPassant 好建议,但这听起来像是密码管理器。显然,密码管理器不能只存储哈希值。
  • 请注意,Microsoft 现在建议避免在新开发中使用 SecureString:github.com/dotnet/platform-compat/blob/master/docs/DE0001.md

标签: c# security memory securestring


【解决方案1】:

SecureString 将其文本加密保存在内存中,您可以在不需要时立即将其丢弃。问题是,当你想显示它或以几乎任何其他方式使用它时,你必须将它转换为普通字符串,这是不安全的。

另外,我不会过分依赖它——系统无需任何解密密钥即可对其进行解密,这意味着有决心的黑客很可能也能做到这一点。当黑客控制您的计算机时,您无法确定任何事情,他很可能能够访问未使用良好算法和良好密钥加密的任何内容。

【讨论】:

    【解决方案2】:

    SecureString 以某种方式保护字符串的内存实例,但是您应该注意一些重大缺陷。

    • 可以在没有解密密钥的情况下检索 SecureString(正如 svick 指出的那样),因此任何熟练到可以检索这块内存的黑客都可以放心地假设可以轻松地执行这个小操作来检索纯文本字符串。考虑SecureStringToBSTR(input); 的简单性
    • SecureString 需要以逐个字符的方式填充,因为没有 .Text 属性 Get 或 Set 访问器可供使用。在包括 MSDN 在内的博客上,您经常会看到如下代码:

      public static SecureString StringToSecureString(string input)
      {
          SecureString output = new SecureString();
          int l = input.Length;
          char[] s = input.ToCharArray(0, l);
          foreach (char c in s)
          {
              output.AppendChar(c);
          }
          return output;
      }
      

    此代码的重要问题是开发人员允许input 字符串永远 存在于内存中。用于从用户那里收集此密码的 PasswordBox 的用户控件或 WinForm TextBox 绝不应该在一次操作中收集整个密码,因为

    • 黑客可以直接访问内存并直接从堆栈上的控件中检索密码,也可以在此方法的实例化上注入代码以检索密码
    • 如果上次蓝屏时您的最后一个内存转储仍然驻留在您的计算机上,并且此控件中填充了您的纯文本密码,那么该密码位于一个整洁的小文件中,可供黑客获取和使用在他/她的空闲时间。

    请考虑使用 KeyPress 从用户那里检索每个字符的选项,否则,我相信 WPF 的 PasswordBox 默认由 SecureString 支持(其他人可能会确认这一点)。

    最后,还有更简单的方法可以从 Key Loggers 等用户那里收集密码。我的建议是考虑您的用户人口统计、暴露风险,并确定像 SecureString 这样的琐碎的东西是否真的会减少它。

    【讨论】:

    • 非常有趣!
    • @ScottShaw-Smith,我知道这已经过时了,但我不认为他建议使用键盘记录器作为“解决此问题的可行方法”。相反,他是说如果黑客使用键盘记录器,使用 SecureString+KeyPress 并不能帮助保护密码。
    【解决方案3】:

    SecureString 正是名字所说的,你猜到了:它把字符串保存在内存中,也是加密的,所以是的,这是正确的方法。
    HERE

    表示应该保留的文本 机密的。文本已加密 使用时保护隐私,以及 没有时从计算机内存中删除 更需要。这个类不能 继承。

    【讨论】:

      【解决方案4】:

      你们把这种方式弄得太复杂了。没有人问这是否是解决问题的最佳方法。他们只是想看看一些工作代码。天哪。在此示例中,passwordPre 是使用您的专有解密算法从资源(例如配置文件)中解密的字符串。

          string passwordPre = DecryptProprietary(objectReferringToPassword);
          char[] passwordChars = passwordPre.ToCharArray();        
          System.Security.SecureString securePassword = new System.Security.SecureString(); // in production, this should probably be a global variable
          foreach (char c in passwordChars)
              securePassword.AppendChar(c);
      
          string decryptedPassword = new System.Net.NetworkCredential(string.Empty, securePassword).Password; // this is how to convert it to a string for quick usage to access the protected resource
      

      因此,您可以快速使用解密的密码来访问您需要的任何资源,然后通过退出该方法来处理它。

      【讨论】:

      • 我真的很讨厌人们在没有任何解释的情况下投反对票,所以我不会投反对票,但我会分享我对为什么这个样本存在严重缺陷的看法:SecureString 的全部意义在于加密可变字节数组与将敏感数据存储在不可变字符串中。由于不可变字符串的垃圾收集是非确定性的,因此您的敏感数据可能在 SecureString 被处置后很长时间仍存在于内存中,从而使其使用完全没有意义。
      猜你喜欢
      • 1970-01-01
      • 2016-05-05
      • 2018-01-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多