从内存中清除C#字符串

rai*_*syn 20 c# memory security string securestring

我出于安全原因试图清除C#字符串的内存内容.我知道的SecureString类,但不幸的是我不能使用SecureString,而不是String在我的应用程序.需要清除的字符串是在运行时动态创建的(例如,我不是要清除字符串文字).

我发现的大多数搜索结果基本上都说清除a的内容String是不可能的(因为字符串是不可变的)并且SecureString应该使用.

因此,我确实在下面提出了我自己的解决方案(使用不安全的代码).测试显示解决方案有效,但我仍然不确定解决方案是否有任何问题?还有更好的吗?

static unsafe bool clearString(string s, bool clearInternedString=false) 
{
    if (clearInternedString || string.IsInterned(s) == null)
    {
        fixed (char* c = s)
        {
            for (int i = 0; i < s.Length; i++)
                c[i] = '\0';
        }
        return true;
    }
    return false;
}
Run Code Online (Sandbox Code Playgroud)

编辑:由于GC的注释在clearString被调用之前移动字符串:下面的代码片段怎么样?

string s = new string('\0', len);
fixed (char* c = s)
{
    // copy data from secure location to s
    c[0] = ...;
    c[1] = ...;
    ...

    // do stuff with the string

    // clear the string
    for (int i = 0; i < s.Length; i++)
        c[i] = '\0';
}
Run Code Online (Sandbox Code Playgroud)

kem*_*002 17

你的问题是字符串可以移动.如果GC运行,它可以将内容移动到新位置,但不会将旧位置清零.如果您确实将相关字符串清零,则无法保证内存中的其他位置不存在其副本.

这是.NET垃圾收集器的链接,它讨论了压缩.

编辑:这是你的更新问题:

// do stuff with the string
Run Code Online (Sandbox Code Playgroud)

问题是,一旦它离开你的控制,你就失去了确保它安全的能力.如果它完全在您的控制之下,那么您将没有仅使用字符串类型的限制.简而言之,这个问题已存在很长时间了,没有人提出一种安全的方法来处理这个问题.如果你想保证它的安全,最好通过其他方式处理.清除字符串意味着阻止某人通过内存转储找到它.如果您不能使用安全字符串,则停止此操作的最佳方法是限制访问运行代码的计算机.

  • 不,它不是因为他传递的字符串为零.没有人知道在调用函数之前会发生什么. (2认同)

wil*_*ien 11

除了标准的"你正在进入不安全的领域"的答案,我希望解释一下,请考虑以下几点:

CLR不保证在任何给定点只有一个字符串实例,并且它不保证字符串将被垃圾收集.如果我要做以下事情:

var input = "somestring";
input += "sensitive info";
//do something with input
clearString(input, false);
Run Code Online (Sandbox Code Playgroud)

这是什么结果?(我们假设我没有使用字符串文字,而这些是来自某种某种环境的输入)

创建一个字符串,其内容为"somestring".另一个字符串是使用"敏感信息"的内容创建的,而另一个字符串是使用"somestringsensitive info"的内容创建的.只清除后一个字符串:"敏感信息"不是.它可能会也可能不会立即被垃圾收集.

即使您小心确保始终清除任何包含敏感信息的字符串,CLR仍然不能保证只存在一个字符串实例.

编辑: 关于您的编辑,只需立即固定字符串可能会产生所需的效果 - 无需将字符串复制到另一个位置或任何其他位置.您确实需要在收到所述字符串后立即执行此操作,并且还有其他安全问题需要担心.例如,你不能保证字符串的来源在ITS内存中没有它的副本,而没有清楚地理解源以及它是如何做的.

由于显而易见的原因,你也无法改变这个字符串(除非变异的字符串与字符串的大小完全相同),你需要非常小心,你所做的一切都不能踩到不是的内存.该字符串的一部分.

此外,如果您将其传递给您自己未编写的其他功能,则该功能可能会复制也可能不会复制.


xxb*_*bcc 5

在您尝试清除字符串之前,无法确定字符串经过多少次CLR和非CLR函数.这些函数(托管和非托管)可能由于各种原因(可能是多个副本)创建字符串的副本.

你不可能知道所有这些地方,并且如此逼真地清除它们,你不能保证你的密码是从内存中清除的.您应该使用SecureString相反,但您需要了解上述内容仍然适用:在您的程序中的某个时刻,您将收到密码,并且您必须将其保存在内存中(即使只是在您移动它的过程中持续一段时间)进入一个安全的字符串).这意味着您的字符串仍将通过您无法控制的函数调用链.