用例是在c#中的内存编程中保护字符串。 Microsoft本身不鼓励使用SecureString(https://docs.microsoft.com/en-us/dotnet/api/system.security.securestring?view=netframework-4.7.2)类。
我想知道它是否可以替代:
有什么建议吗?
答案 0 :(得分:3)
SecureString
类无可替代。微软鼓励使用的“替代方案” here:
处理凭据的一般方法是避免使用凭据,而是依靠其他方式进行身份验证,例如证书或Windows身份验证。
因此,如果您真的需要凭据并且没有其他方法:在.NET Framework上,使用SecureString
。对于.NET Core,目前没有其他选择。
答案 1 :(得分:3)
因此,您要问的基本问题是“由于Microsoft不鼓励使用SecureString的用户,我可以自己推出吗?”。
好吧,除了您的实现可能不如Microsoft原始版本安全之外,它还会至少存在相同的问题,因为它们不是针对特定的实现,而是针对这个概念。
如果要使用该概念,则也可以使用SecureString。解决方案是不要在内存中使用加密凭据的概念,既不要与Microsoft的类一起使用,也不要与您自己的自制软件一起使用。
答案 2 :(得分:2)
我不会说它“被Microsoft吓坏了”-这太过简单了。实际的原因在本页(https://github.com/dotnet/platform-compat/blob/master/docs/DE0001.md中给出了,该参数似乎是“在.NET Core中使用它不值得”,也不是说它总体上并不安全。 >
我认为SecureString
是是安全的……但仅适用于Windows上的.NET Framework。我链接到的页面来自跨平台的.NET Core项目-因此,劝阻或禁止在.NET Core中使用SecureString
是有意义的-但是,如果您的项目针对的是.NET Framework(是Windows专有的)或针对Windows的.NET Core -那么就可以了。引号如下(强调我的意思):
该数组的内容未加密 .NET Framework上的除外。
顺便说一句,{TW} SecureString
可以安全地用于避免内存中的明文,如果您仅通过使用其SecureString
方法将秘密直接直接读取到Append
中。从控制台读取密码(伪代码)时,这非常有用:
Console.WriteLine( "Enter your password" );
SecureString password = new SecureString();
while( Char c = Console.ReadKey() != '[Enter'] ) {
password.Append( c );
}
...但是,如果以后需要访问该字符串的明文版本,则它的安全性较低(尽管希望明文字符串可以由GC收集为第0代对象)。
关于您的建议:
- 将字符串转换为字节数组,然后立即将字符串设置为null(并最终调用垃圾收集器)
- 使用ProtectedMemory类对字节数组进行加密。
这确实是SecureString的工作方式,它仍然遇到相同的问题:加密内容的明文副本在内存中仍然存在很短的时间-这就是问题所在。
答案 3 :(得分:0)
tl;dr:SecureString 是个好主意。微软不再推荐它的原因是.NET Core不能拥有它,因为Linux不支持加密。
您需要 SecureString 的原因有两个。
第一个是 HeartBleed 攻击的思路,原因是 SecureZeroMemory 存在,以及 Windows 在给你之前总是归零一页内存的原因:避免泄漏信息。
<块引用>终端服务在 RAM 中保持未加密的用户密码。
第二个,也是 SecureString 存在于 .NET 中的原因,是因为您无法调用 SecureZeroMemory。 .NET 中的字符串是不可变的,您无法控制它们的生命周期。
所以为了解决这个问题,有两个要素:
当它是一个数组时,意味着您可以擦除内容。这意味着当您完成敏感的信用卡号、比特币私钥、密码、英特尔蓝光主密钥时,您可以做与 ZeroMemory
相同的道德行为:您可以擦除它们
这解决了完全无法擦除C#字符串
的问题CryptProtectData
加密另一个,无关,SecureString 的优点是原始字符串不会出现在内存转储、虚拟机 RAM 快照、Web 服务器日志、调试器监视窗口中。或者在HeartBleed 攻击的情况下,不会出现在分发给其他网站用户的未初始化数据中。
这是 SecureString 提供的两个核心元素。
两者都可以复制。 .NET Core 没有它们的原因并不是因为 SecureString 是一个坏主意、一个浪费的主意、一个不完整的主意,或者 “没有兑现承诺”。相反,这是因为 Linux 没有 CryptProtectData
的等价物。由于 .NET Core 必须是跨平台的,因此它们必须满足最小公分母的需求。所以他们举起手说把它拿掉。
但 SecureString 与以下概念一样有效:
否则任何人都在说谎。
您想使用 SecureString
CryptProtectData
存在CryptProtectMemory
存在这是否意味着信用卡号在某些时候以明文形式存在于内存中:
<块引用>不,原因是它的用途非常有限,并且在大多数情况下,该字符串要么保留在内存中,要么重新出现。原始字符串保留在内存中,直到它成为 GCd。并且由于 SecureString 在 Win32 API(或 Linux)中没有对应项,一旦应用程序尝试对其执行任何操作,原始字符串就会重新出现。即使在 SDK 中,也只有 NetworkCredentials 正确使用了它,而 SecureString 不是 Windows 概念,所以一旦你使用 Windows API,它就会被转换回来。
但我们必须意识到的是:
这些是好的纵深防御措施。
任何人说不同的都是错误的。