46

如果我理解正确,这是为了将纯文本保留在内存之外,这样应用程序就可以安全地抵御对内存、垃圾堆或分页到磁盘的内存的深奥攻击。SecureString 被馈入非托管字节并一次消耗一个非托管字节 - 然后从内存中删除该字符串。(如果我离开,请纠正我!)

在 ASP.NET 中,秘密被收集在一个 web 表单中,该表单以 HTTPS 回发。但随后 Request 对象将表单中的所有请求值转换为名称值对并将它们放入一个集合中,例如 Request["TxtPassword"]——所以即使在我得到字符串之前,它已经被不安全地写入内存。更糟糕的是,如果我使用的是控件,那么不安全的表示将在 TextBox 的属性中包含更多托管字符串。

要对这个 SecureString 做任何事情,我需要一个接受非托管字符串的 API——所以看来我不能将安全字符串用于存储的 proc 参数或其他许多参数。

我做错了还是尝试使用 SecureString 而不是将不安全字符串的副本泄漏到托管内存中是愚蠢的差事?

切换到 OAuth 或 Windows 身份验证不是一种选择。

4

5 回答 5

29

正如您正确推断的那样,以及其他人已经提到的,使用SecureString存储来自 ASP.NET 表单的安全敏感数据几乎没有意义,因为该数据已经以纯文本形式存在于内存中。

但是,在其他情况下,SecureString建议使用 ,因为敏感数据是由程序本身创建的,并且在完成处理后不应保留在内存中。例如,以编程方式创建 SharePoint 站点,或将身份验证凭据从一个系统传输到另一个系统。

回到过去的美好时光,确保敏感数据的生命周期尽可能短更容易。它可以在堆栈上分配并在程序使用完后立即清除:

char secret[512];
generate_secret(secret, sizeof(secret));
do_something_with(secret);
memset(secret, 0, sizeof(secret));
// Secret data is now gone.

但是,这种方法对于托管字符串是不可能的,主要是因为:

  • 它们没有分配在堆栈上,
  • 它们是不可变的,因此无法清除,
  • 它们不是一次性的,因此无法保证 GC 何时释放数据。它甚至可能永远不会被释放,具体取决于内存条件。

SecureString试图通过可变和一次性来解决这个问题,这允许人们编写:

using (SecureString secret = new SecureString()) {
    GenerateSecret(secret);
    secret.MakeReadOnly();
    DoSomethingWith(secret);
}
// Secret data is now gone.
于 2010-12-17T09:35:36.687 回答
7

SecureString 最适合用于为系统之间的直接调用分配网络凭据。在网络领域,如果凭证通过网络进入,它在某处以明文形式出现,但如果您必须通过标准凭证调用(ftp、目录服务等)将该凭证发送回,那么使用 SecureString不伤作为传球方法。虽然您是正确的,该字符串已经以纯文本形式存在于您的服务器系统上,但您至少可以减少系统之间的占用空间。如果您仅在本地使用此密码,那么我同意 SecureString 可能不是非常必要。

但是,良好的安全习惯绝不是浪费时间。

于 2010-12-16T18:31:55.463 回答
6

我认为你有它的基础。SecureString 是从位于客户端的角度设计的。因此,对于 WPF/Winforms 应用程序(也许是 Silverlight,不记得它是否在其中),对于服务器端应用程序来说,它是值得的,而不是因为不是第一个处理字符串的人。

于 2010-12-16T18:28:33.170 回答
2

我唯一一次标记SecureString在执行安全代码审查时缺少使用的情况是数据可能被应用程序加密并重用的情况。

例如,当网站后端需要与第三方或其他需要凭据的内部资源进行通信时。由于这些不能被散列,我会SecureString在需要构建请求时使用(也应该通过 TLS)。

另一种选择是尽可能使用Windows 数据保护 API

请注意, 的目的SecureString是尽可能短的将内容保存在内存中。

于 2016-06-10T16:55:06.410 回答
-1

如果我没记错的话,您可以使用以下解决方案将输入排除在 CLR 的字符串管理之外: Web API:使用 MultipartMemoryStreamProvider 时如何访问多部分表单值?

仅将 ExecutePostProcessingAsync(..) 方法中的 FormData 读取为 ReadAsByteArrayAsync() 并且它永远不应该成为一个字符串。

您仍然需要 https 来保证输入的安全。

于 2016-02-16T13:18:33.963 回答