所以有一个似乎很少使用的类:SecureString。它至少从 2.0 开始就已经存在,并且有一些 SO 问题,但我想我会问我自己的具体问题:
我有一个登录表单;带有用户名和(屏蔽)密码字段的简单 WinForms 对话框。当用户同时输入并单击“登录”时,信息被传递给一个注入的身份验证类,该类执行一层密钥拉伸,然后对拉伸密钥的一半进行散列以进行验证,而另一半是加密用户的对称密钥账户数据。当这一切都完成后,loginForm 被关闭,身份验证器类被释放,系统继续加载主表单。相当标准的东西,可能比标准的哈希密码和比较涉及更多,但在我的情况下,通过以明文形式存储用户数据,简单的哈希密码将被击败,因为该数据包括第三个的凭据-派对系统(我们都知道人们喜欢重用密码)。
这是第一个问题;我将如何使用 SecureString 从 Password 文本框中检索密码,而不会通过文本框的 Text 属性将其公开为普通 System.String?我假设有一种方法可以访问由 CLR 类包装的文本框的非托管 GDI 窗口,并使用 Marshal 类提取文本数据。我只是不知道如何,我似乎无法找到好的信息。
这是第二个问题;将密码作为 SecureString 后,如何将其从 System.Security.Crypto 命名空间传递给哈希提供程序?我的猜测是我会使用 Marshal.SecureStringToBSTR(),然后从返回的 IntPtr 使用 Marshal.Copy() 回到字节数组中。然后我可以调用 Marshal.ZeroBSTR() 来清理非托管内存,并且一旦我有了哈希值,我就可以使用 Array.Clear() 将托管数组清零。如果有一种更简洁的方法可以让我完全控制内存的任何托管副本的生命周期,请告诉我。
第三个问题;这一切真的有必要吗,或者 System.String 在托管内存环境中固有的不安全性有点夸大其词?任何用于存储密码的东西,无论是加密的还是其他的,都应该在操作系统考虑将应用程序交换到虚拟内存之前(允许在硬关机)。冷启动攻击是一种理论上的可能性,但实际上,这有多普遍?更大的担忧是现在解密的用户数据,它作为用户的一部分在整个应用程序生命周期内一直存在(因此将成为使用 SecureStrings 的主要候选者,除了它们保持相当休眠的几个基本用法)。