如果我的假设在这里错了,请随意纠正我,但让我解释一下我为什么要问.
摘自MSDN,a SecureString:
代表应保密的文本.文本在使用时加密以保护隐私,并在不再需要时从计算机内存中删除.
我明白了,将密码或其他私人信息存储在a中是完全合理SecureString的System.String,因为你可以控制它实际存储在内存中的方式和时间,因为System.String:
是不可变的,当不再需要时,不能以编程方式安排垃圾收集; 也就是说,实例在创建后是只读的,并且无法预测实例何时从计算机内存中删除.因此,如果String对象包含敏感信息(如密码,信用卡号或个人数据),则使用该信息后可能会显示该信息,因为您的应用程序无法从计算机内存中删除该数据.
但是,在GUI应用程序(例如,ssh客户端)的SecureString 情况下,必须从a构建 System.String.所有文本控件都使用字符串作为其基础数据类型.
因此,这意味着每次用户按下某个键时,就会丢弃那里的旧字符串,并构建一个新字符串来表示文本框内的值,即使使用密码掩码.并且我们无法控制何时或是否从内存中丢弃任何这些值.
现在是时候登录服务器了.你猜怎么着?您需要在连接上传递一个字符串以进行身份验证.所以让我们将我们SecureString转换为System.String....现在我们在堆上有一个字符串,无法强制它通过垃圾收集(或将0写入其缓冲区).
我的观点是:无论你做什么,沿线某处,那SecureString是会被转换成一个System.String,这意味着它至少会在某些点上堆存在(没有垃圾收集的任何保证).
我的观点不是:是否存在绕过将字符串发送到ssh连接或绕过控件存储字符串(制作自定义控件)的方法.对于这个问题,您可以将"ssh connection"替换为"登录表单","注册表单","付款表单","食物 - 你愿意喂你的小狗但不是你孩子的表格",等等
SecureString实际变得实用?System.String对象的使用?SecureString减少System.String堆上的时间(降低转移到物理交换文件的风险)?SecureString阻止他进入数据呢?对不起,如果我把问题放得太厚,好奇心就好了.随意回答我的任何或所有问题(或告诉我,我的假设是完全错误的).:)
Ert*_*maa 230
实际上有非常实际的用途SecureString.
你知道我见过这种情景多少次了吗?(答案是:很多!):
RedGate软件可以捕获局部变量的"值",以防异常,非常有用.虽然,我可以想象它会意外地记录"字符串密码".你知道如何避免所有这些问题吗?SecureString.它通常会确保你不会犯这样的愚蠢错误.它是如何避免它的?通过确保密码在非托管内存中加密,只有在90%确定您正在执行的操作时才能访问实际值.
从某种意义上说,SecureString非常容易:
1)一切都是加密的
2)用户来电 AppendChar
3)解密UNMANAGED MEMORY中的所有内容并添加角色
4)在UNMANAGED MEMORY中再次加密所有内容.
如果用户可以访问您的计算机怎么办?病毒是否能够访问所有病毒SecureStrings?是.您需要做RtlEncryptMemory的就是在解密内存时自己进入,您将获得未加密的内存地址的位置,并将其读出.瞧!实际上,您可以制作一种病毒,该病毒会不断扫描其使用情况SecureString并记录所有活动.我并不是说这将是一件容易的事,但可以做到.正如您所看到的,SecureString一旦系统中存在用户/病毒,"强大" 就完全消失了.
你的帖子中有几点.当然,如果您在内部使用一些保存"字符串密码"的UI控件,那么使用实际SecureString操作并不是那么有用.虽然,它仍然可以防止我上面列出的一些愚蠢.
此外,正如其他人所说,WPF支持PasswordBox,它SecureString通过其SecurePassword属性在内部使用.
底线是; 如果您有敏感数据(密码,信用卡,..),请使用SecureString.这就是C#Framework所遵循的.例如,NetworkCredential类将密码存储为SecureString.如果你看看这个,你可以看到在在.NET框架〜80种不同的用途SecureString.
在许多情况下,您必须转换SecureString为字符串,因为某些API需要它.
通常的问题是:
你提出了一个好点:SecureString转换成什么时会发生什么string?这只能因为第一点而发生.例如,API不知道它是敏感数据.我个人没有看到过这种情况.从SecureString中获取字符串并不是那么简单.
由于一个简单的原因,这并不简单 ; 它从来没有打算让用户将SecureString转换为字符串,正如你所说:GC会启动.如果你看到自己这样做,你需要退后一步问自己:为什么我甚至这样做,或者我真的需要这个,为什么?
我看到了一个有趣的案例.即,WinApi函数LogonUser将LPTSTR作为密码,这意味着您需要调用SecureStringToGlobalAllocUnicode.这基本上为您提供了未加密的密码,该密码位于非托管内存中.一旦你完成,你需要摆脱它:
// Marshal the SecureString to unmanaged memory.
IntPtr rawPassword = Marshal.SecureStringToGlobalAllocUnicode(password);
try
{
//...snip...
}
finally
{
// Zero-out and free the unmanaged string reference.
Marshal.ZeroFreeGlobalAllocUnicode(rawPassword);
}
Run Code Online (Sandbox Code Playgroud)
您始终可以SecureString使用扩展方法扩展该类,例如ToEncryptedString(__SERVER__PUBLIC_KEY),使用服务器的公钥加密您的string实例SecureString.只有服务器可以解密它.问题解决了:垃圾收集永远不会看到"原始"字符串,因为您从未在托管内存中公开它.这正是在PSRemotingCryptoHelper(EncryptSecureStringCore(SecureString secureString))中所做的.
而且几乎相关的东西:Mono SecureString根本不加密.该实现已被注释掉,因为..等待它.. "它以某种方式导致nunit测试破坏",这带来了我的最后一点:
SecureString在任何地方都不受支持.如果平台/体系结构不支持SecureString,您将获得异常.文档中支持的平台列表.
Dam*_*ash 15
在你的假设中几乎没有问题.
首先,SecureString类没有String构造函数.为了创建一个,你分配一个对象,然后附加字符.
对于GUI或控制台,您可以非常轻松地将每个按下的键传递给安全字符串.
该类的设计方式是您不能错误地访问存储的值.这意味着您无法string直接从中获取密码.
因此,对于使用它,例如,通过Web进行身份验证,您将必须使用也是安全的适当类.
在.NET框架中,您有一些可以使用SecureString的类
总而言之,SecureString类可能很有用,但需要开发人员给予更多关注.
所有这些,以及示例,都在MSDN的SecureString文档中有详细描述
Joe*_*Joe 10
在以下情况下,SecureString非常有用:
您逐个字符地构建它(例如从控制台输入)或从非托管API获取它
您可以通过将其传递给非托管API(SecureStringToBSTR)来使用它.
如果你将它转换为托管字符串,你就已经失败了.
更新以回应评论
......或者像你提到的BSTR,这似乎不再安全
在转换为BSTR之后,使用BSTR的非托管组件可以将内存归零.非托管内存在以这种方式重置的意义上更安全.
但是,.NET Framework中支持SecureString的API很少,因此您可以说它今天的价值非常有限.
我将看到的主要用例是在客户端应用程序中,要求用户输入高度敏感的代码或密码.可以逐个字符地使用用户输入来构建SecureString,然后可以将其传递给非托管API,该API在使用它之后将其接收的BSTR归零.任何后续内存转储都不包含敏感字符串.
在服务器应用程序中,很难看出它在哪里有用.
更新2
接受SecureString的.NET API的一个示例是X509Certificate类的构造函数.如果您使用ILSpy或类似的东西,您将看到SecureString在内部转换为非托管缓冲区(Marshal.SecureStringToGlobalAllocUnicode),然后在完成(Marshal.ZeroFreeGlobalAllocUnicode)时归零.
Microsoft 不建议将其SecureString用于较新的代码。
从SecureString Class 的文档中:
重要的
我们不建议您将该
SecureString类用于新的开发。有关更多信息,请参阅SecureString不应使用
其中推荐:
不要
SecureString用于新代码。将代码移植到 .NET Core 时,请考虑数组的内容在内存中未加密。处理凭证的一般方法是避免使用凭证,而是依靠其他方式进行身份验证,例如证书或 Windows 身份验证。在 GitHub 上。