2013-01-22 25 views
12

所以这个类似乎很少使用:SecureString。至少从2.0版开始,有几个SO问题,但我想我会问自己的具体问题:安全使用SecureString登录表格

我有一个LoginForm;带有用户名和(被屏蔽的)密码字段的简单WinForms对话框。当用户同时输入并单击“登录”时,信息被传递给一个注入的认证类,它执行一层密钥扩展,然后将一半的扩展密钥用于验证,而另一半则是加密用户的对称密钥账户数据。当所有这些都完成后,loginForm关闭,处理验证器类,然后系统继续加载主表单。相当标准的东西,可能比标准的hash-the-password-and-compare有更多的参与,但是简单的散列密码在我的情况下会以明文方式存储用户数据,因为这些数据包括第三方密码,第三方系统(我们都知道人们喜欢重复使用密码)。

这是第一个问题;我将如何使用SecureString从密码文本框中检索密码,而不是它通过文本框的Text属性显示为普通的System.String?我假设有一种方法可以访问由CLR类包装的文本框的非托管GDI窗口,并使用Marshal类拉取文本数据。我只是不知道如何,我似乎无法找到好的信息。

这是第二个问题;一旦我将密码作为SecureString使用,我如何将它从System.Security.Crypto命名空间传递给哈希提供程序?我的猜测是,我会使用Marshal.SecureStringToBSTR(),然后Marshal.Copy()从返回的IntPtr返回到一个字节数组。然后,我可以调用Marshal.ZeroBSTR()来清理非托管内存,并且一旦有散列,我就可以用Array.Clear()清零托管数组。如果有一种更清晰的方式可以让我完全控制内存中任何托管副本的生命周期,请告诉。

第三个问题;所有这些都是非常必要的,或者是在托管内存环境中System.String固有的不安全性有点过分?任何用于存储密码,加密或其他方式,应该超出了作用域,并且在操作系统考虑将应用程序交换到虚拟内存之前就已经到达垃圾收集器的路上了(允许从交换文件中嗅探密码在计算机硬关机后)。冷启动攻击是一种理论上的可能性,但真的,这有多常见?更大的担忧是现在解密的用户数据,作为整个应用程序生命周期的用户的一部分而挂起(因此,除了一些基本用法,它们保持相当休眠状态外,它们将成为使用SecureStrings的主要候选项)。

回答

5

如果您认为您需要SecureString您必须相信攻击者也可以读取您的进程内存。如果后者是真的,他可以在输入密码时读取密码字符,也可以直接从文本框内部字符缓冲区中读取密码字符,或从屏幕读取像素。

这是一个不切实际的情况。请勿使用SecureString。它帮助很少,偷走你的时间。

冷启动攻击更真实,但非常罕见。他们需要通常完全拥有机器的物理机器访问权限。 由攻击者阅读是你在这种情况下最担心的问题。

基本上,你必须设计一个案例,其中你的开发人员时间很好用SecureString

+6

这个想法是减少攻击面。例如,如果攻击者无法读取内存,但可以访问交换文件,SecureString可以提供帮助。我们无法预测攻击者可以做什么或不可以做什么,所以我们试图让事情变得非常困难。但是,没有任何保护措施会有帮助:如果应用程序知道这些信息 - 攻击者可能也可以。 –

+0

我猜对于'SecureString'的最佳论据是开发人员的时间最好花在其他地方。 – usr

+2

好吧,我不必相信攻击者可以看到输入的字符,相信攻击者可以提取交换文件。复杂程度和要求的访问水平是非常不同的。所以,我可以预见SecureString的一个优势是在一个不需要过多设计的情况下需要长期保存在内存中的敏感数据(比如前面提到的第三方系统凭证,只要应用程序能够运行并且最终可以结束交换文件)。但我认为我同意你的观点,即10倍中的9倍比它的价值更麻烦。 – KeithS

3

首先,我想说明我同意usr - 不要打扰。

我们的细节:

  • This答案提供了讨论的大背景。
  • This是一个使用SecureString的TextBox控件。我没有 使用这个,所以我不能评论的质量,但在MS博客我 不要指望它是什么,但不正确。
  • 要回答有关将数据传递给System.Security.Crypto的问题,基本上,您的 不能,也不会有大量的非托管内存编组将帮助您,因为在此类编组过程中字符串会被解密。它必须因为否则它不能被您的目标API使用。如果您使用的是CSP或X509Certificate,则可以使用SecureSctring,因为它们在框架中受支持,但就是这样。
+0

我不认为问题是在解密字符串(不可否认,我的知识很少)。我认为问题在于生成一个System.String,开发人员无法控制其生命周期;它是在堆上创建的,只要GC没有收集它(在交换到VM之前可能会发生,也可能不会发生)。一个字节数组OTOH可以就地归零,并且非托管的IntPtr也可以正确清理并释放,所有这些都有希望在CPU高速缓存或RAM中,而不是交换文件,因为它正在被积极使用。 – KeithS

+0

那么,你不应该真的在计数零字节数组。垃圾收集器随时随地刷新内存,可能会有多个字节数组的副本。如果你的目标API被管理,那么你对后面的类型几乎没有任何控制。 –

+0

如果GC的移动内存(正如我所知道的那样),我希望它在堆优化期间或之后清理本身。我相信GC能够以一种有效的方式处理内存,因为如果我想在一个托管的运行时中工作,我就无能为力了(我这样做,因为它比VC++更容易)。但是,我知道GC不在我的叮and声中,这是在受管运行时编写安全代码时的主要问题。 – KeithS