如果我的假设是错误的,请随意纠正我,但让我解释为什么我问。

取自MSDN,一个SecureString:

表示应保密的文本。在使用时,文本会被加密以保护隐私,当不再需要时,会从计算机内存中删除。

我明白了,在系统上的SecureString中存储密码或其他私人信息是完全有意义的。字符串,因为您可以控制它实际存储在内存中的方式和时间,因为System。字符串:

is both immutable and, when no longer needed, cannot be programmatically scheduled for garbage collection; that is, the instance is read-only after it is created and it is not possible to predict when the instance will be deleted from computer memory. Consequently, if a String object contains sensitive information such as a password, credit card number, or personal data, there is a risk the information could be revealed after it is used because your application cannot delete the data from computer memory.

然而,对于GUI应用程序(例如ssh客户端),SecureString必须从System.String构建。所有文本控件都使用字符串作为其底层数据类型。

因此,这意味着每当用户按下一个键时,旧的字符串就会被丢弃,并构建一个新字符串来表示文本框内的值,即使使用密码掩码也是如此。我们无法控制何时或是否将这些值从内存中丢弃。

现在是时候登录到服务器了。你猜怎么着?您需要在连接上传递一个字符串进行身份验证。让我们把SecureString转换为System.String....现在我们在堆上有一个字符串,没有办法强制它进行垃圾收集(或将0写入缓冲区)。

我的观点是:无论你做什么,在某个地方,那个SecureString会被转换成一个系统。字符串,这意味着它至少在某个时候存在于堆上(没有任何垃圾收集的保证)。

我的观点不是:是否有方法可以避免向ssh连接发送字符串,或者避免让控件存储字符串(创建自定义控件)。对于这个问题,您可以将“ssh连接”替换为“登录表单”、“注册表单”、“支付表单”、“你要喂你的小狗但不是你的孩子的食物表单”等等。

So, at what point does using a SecureString actually become practical? Is it ever worth the extra development time to completely eradicate the use of a System.String object? Is the whole point of SecureString to simply reduce the amount of time a System.String is on the heap (reducing its risk of moving to a physical swap file)? If an attacker already has the means for a heap inspection, then he most likely either (A) already has the means to read keystrokes, or (B) already physically has the machine... So would using a SecureString prevent him from getting to the data anyways? Is this just "security through obscurity"?

如果我的问题问得太过分了,对不起,我只是被好奇心控制了。请随意回答我的任何或所有问题(或者告诉我我的假设是完全错误的)。:)


当前回答

你的假设有几个问题。

首先,SecureString类没有String构造函数。为了创建一个对象,你分配一个对象,然后追加字符。

在GUI或控制台的情况下,您可以很容易地将每个按下的键传递给一个安全字符串。

该类的设计方式使您无法访问所存储的值。这意味着您不能直接从该字符串获取作为密码的字符串。

因此,为了使用它,例如,通过web进行身份验证,您将必须使用适当的类,这些类也是安全的。

在.NET框架中,有一些类可以使用SecureString

WPF的PasswordBox控件在内部将密码保存为SecureString。 System.Diagnostics。ProcessInfo的Password属性是一个SecureString。 X509Certificate2的构造函数接受一个SecureString作为密码。

(更多)

综上所述,SecureString类可能很有用,但需要开发人员多加注意。

所有这些都在MSDN的SecureString文档中有详细的描述

其他回答

以下文本是从HP Fortify静态代码分析器复制的

文摘: PassGenerator.cs中的PassString()方法以不安全的方式存储敏感数据(即以字符串形式存储),使得提取敏感数据成为可能 通过检查堆来获取数据。

Explanation: Sensitive data (such as passwords, social security numbers, credit card numbers etc.) stored in memory can be leaked if it is stored in a managed String object. String objects are not pinned, so the garbage collector can relocate these objects at will and leave several copies in memory. These objects are not encrypted by default, so anyone who can read the process' memory will be able to see the contents. Furthermore, if the process' memory gets swapped out to disk, the unencrypted contents of the string will be written to a swap file. Lastly, since String objects are immutable, removing the value of a String from memory can only be done by the CLR garbage collector. The garbage collector is not required to run unless the CLR is low on memory, so there is no guarantee as to when garbage collection will take place. In the event of an application crash, a memory dump of the application might reveal sensitive data.

建议: 将敏感数据存储在SecureString对象中,而不是存储在string等对象中。对象中存储其内容 在内存中始终保存加密格式。

我想谈谈这一点:

如果攻击者已经有了堆检查的方法,那么他们很可能要么(a)已经有了读取击键的方法,要么(B)已经在物理上拥有了机器……那么使用SecureString会阻止他们获取数据吗?

攻击者可能没有对计算机和应用程序的完全访问权,但可以有方法访问进程内存的某些部分。当特殊构造的输入可能导致应用程序公开或覆盖某些内存时,这通常是由缓冲区溢出之类的错误引起的。

HeartBleed内存泄漏

以《Heartbleed》为例。特殊构造的请求可能导致代码将进程内存的随机部分暴露给攻击者。攻击者可以从内存中提取SSL证书,但他唯一需要做的就是使用一个畸形的请求。

在托管代码的世界中,缓冲区溢出成为一个不太常见的问题。在WinForms的情况下,数据已经以不安全的方式存储,您无法对此做任何事情。这使得使用SecureString的保护几乎毫无用处。

但是,GUI可以被编程为使用SecureString,在这种情况下,减少内存中可用密码的窗口是值得的。例如,PasswordBox。WPF中的SecurePassword是SecureString类型。

正如您已经正确识别的那样,SecureString相对于string提供了一个特定的优势:确定性擦除。这一事实有两个问题:

As others have mentioned and as you have noticed by yourself, this isn't enough by itself. You have to make sure that every step of the process (including retrieval of input, construction of the string, usage, deletion, transportation, etc) happens without defeating the purpose of using SecureString. This means that you must be careful to never create a GC-managed immutable string or any other buffer that will store the sensitive information (or you'll have to keep track of that as well). In practice, this isn't always easy to achieve, because lots of APIs only offer a way to work with string, not SecureString. And even if you do manage to everything right... SecureString protects against very specific kinds of attack (and for some of them, it's not even that reliable). For example, SecureString does allow you to shrink the time window in which an attacker can dump the memory of your process and successfully extract the sensitive information (again, as you correctly pointed out), but hoping that the window is too small for the attacker to take a snapshot of your memory isn't considered security at all.

那么,什么时候应该使用它呢?只有当您正在使用可以让您使用SecureString满足所有需求的东西时,即使这样,您仍然应该注意,这仅在特定情况下是安全的。

微软不建议对更新的代码使用SecureString。

来自SecureString类的文档:

重要的 我们不建议你使用SecureString类new 发展。有关更多信息,请参见不应该使用SecureString

建议:

不要在新代码中使用SecureString。当将代码移植到。net Core时, 假设数组的内容在内存中没有加密。 处理凭证的一般方法是避免使用它们 相反,依靠其他方法进行身份验证,如证书或 Windows身份验证。

SecureString在以下情况下是有用的:

你可以一个字符一个字符地构建它(例如从控制台输入),或者从非托管API获取它 您可以通过将它传递给非托管API (SecureStringToBSTR)来使用它。

如果您曾经将它转换为托管字符串,那么您就破坏了它的目的。

更新以回应评论

... 或者像你提到的BSTR,这似乎并不安全

在它被转换为BSTR之后,消耗BSTR的非托管组件可以将内存归零。非托管内存更安全,因为它可以以这种方式重置。

然而,在. net框架中支持SecureString的api非常少,所以你说它现在的价值非常有限是对的。

我看到的主要用例是在客户端应用程序中,要求用户输入高度敏感的代码或密码。用户输入可以一个字符一个字符地使用来构建一个SecureString,然后这个可以传递给一个非托管API,它在使用它之后将接收到的BSTR归零。任何后续的内存转储将不包含敏感字符串。

在服务器应用程序中,很难看出它在什么地方有用。

更新2

接受SecureString的. net API的一个例子是X509Certificate类的构造函数。如果您使用ILSpy或类似工具进行深入研究,您将看到SecureString在内部转换为非托管缓冲区(Marshal.SecureStringToGlobalAllocUnicode),然后在使用(Marshal.ZeroFreeGlobalAllocUnicode)完成时将其归零。