Ric*_*gan 179 .net security encryption
我试图了解.NET的SecureString的目的.来自MSDN:
System.String类的一个实例都是不可变的,当不再需要时,不能以编程方式安排垃圾收集; 也就是说,实例在创建后是只读的,并且无法预测实例何时从计算机内存中删除.因此,如果String对象包含敏感信息(如密码,信用卡号或个人数据),则使用该信息后可能会显示该信息,因为您的应用程序无法从计算机内存中删除该数据.
SecureString对象类似于String对象,因为它具有文本值.但是,SecureString对象的值会自动加密,可以修改,直到您的应用程序将其标记为只读,并且可以通过应用程序或.NET Framework垃圾收集器从计算机内存中删除.
初始化实例或修改值时,SecureString实例的值会自动加密.您的应用程序可以呈现实例不可变,并通过调用MakeReadOnly方法防止进一步修改.
自动加密是最大的收益吗?
为什么我不能说:
SecureString password = new SecureString("password");
Run Code Online (Sandbox Code Playgroud)
代替
SecureString pass = new SecureString();
foreach (char c in "password".ToCharArray())
pass.AppendChar(c);
Run Code Online (Sandbox Code Playgroud)
我错过了SecureString的哪个方面?
Chr*_*ham 109
目前使用的框架的某些部分SecureString:
System.Windows.Controls.PasswordBox控件在内部将密码保存为SecureString(作为副本公开PasswordBox::SecurePassword)System.Diagnostics.ProcessStartInfo::Password物业是一个SecureStringX509Certificate2获取SecureString密码的构造函数主要目的是减少攻击面,而不是消除它.SecureStrings在RAM中被"固定",因此垃圾收集器不会移动它或复制它.它还确保纯文本不会写入Swap文件或核心转储.加密更像是混淆,并且不会阻止确定的黑客,谁能够找到用于加密和解密它的对称密钥.
正如其他人所说的那样,你必须创建一个SecureString逐个字符的原因是因为第一个明显的缺点:你可能已经将秘密值作为一个普通的字符串了,那么重点是什么?
SecureStrings是解决Chicken-and-Egg问题的第一步,因此即使大多数当前场景需要将它们转换回常规字符串以完全使用它们,它们在框架中的存在现在意味着更好地支持它们.未来 - 至少到你的程序不一定是薄弱环节的地步.
Ric*_*gan 36
很多很棒的答案; 这是对所讨论内容的快速概述.
Microsoft已实施SecureString类,以便为敏感信息(如信用卡,密码等)提供更好的安全性.它自动提供:
目前,SecureString的使用受到限制,但预计将来会更好地采用.
根据这些信息,SecureString的构造函数不应该只是取一个字符串并将其切片到char数组,因为拼写的字符串会破坏SecureString的目的.
附加信息:
编辑:我发现选择最佳答案很难,因为很多信息很好; 太糟糕了,没有辅助的答案选项.
Ian*_*oyd 20
为什么我不能说:
Run Code Online (Sandbox Code Playgroud)SecureString password = new SecureString("password");
因为现在你有password记忆; 无法擦除它 - 这正是SecureString的要点.
SecureString存在的原因是因为当您完成它时,您无法使用ZeroMemory擦除敏感数据.它的存在是为了解决因 CLR 而存在的问题.
在常规本机应用程序中,您可以调用SecureZeroMemory:
用零填充内存块.
注意:SecureZeroMemory与之相同ZeroMemory,但编译器不会对其进行优化.
问题是你无法调用ZeroMemory或SecureZeroMemory在.NET内部.在.NET中,字符串是不可变的; 你甚至不能像在其他语言中那样覆盖字符串的内容:
//Wipe out the password
for (int i=0; i<password.Length; i++)
password[i] = \0;
Run Code Online (Sandbox Code Playgroud)
所以,你可以做什么?我们如何提供.NET在我们完成时从内存中擦除密码或信用卡号码的能力?
它可以完成的唯一方法是将字符串放在一些本机内存块中,然后可以调用它ZeroMemory.本机内存对象,例如:
在.NET中,完成它们后无法擦除字符串:
Dispose在它们SecureString作为一种传递字符串安全性的方式存在,并且能够在需要时保证它们的清理.
你问了这个问题:
为什么我不能说:
Run Code Online (Sandbox Code Playgroud)SecureString password = new SecureString("password");
因为现在你有password记忆; 无法擦拭它.它一直停留在那里,直到CLR决定重新使用那个内存.你把我们放回了我们开始的地方; 一个正在运行的应用程序,我们无法摆脱密码,内存转储(或进程监视器)可以看到密码.
SecureString使用Data Protection API来存储在内存中加密的字符串; 这样,字符串将不会存在于交换文件,崩溃转储中,甚至在局部变量窗口中,并且同事会查看你的应该.
然后是问题:我如何与字符串交互?你绝对不想要一个像这样的方法:
String connectionString = secureConnectionString.ToString()
Run Code Online (Sandbox Code Playgroud)
因为现在你回到了你开始的地方 - 一个你无法摆脱的密码.您希望强制开发人员正确处理敏感字符串 - 以便可以从内存中擦除它.
这就是为什么.NET提供了三个方便的辅助函数来将SecureString编组到非托管内存中:
您将字符串转换为非托管内存blob,处理它,然后再次擦除它.
一些API接受SecureStrings.例如,在ADO.net 4.5中,SqlConnection.Credential采用一组SqlCredential:
SqlCredential cred = new SqlCredential(userid, password); //password is SecureString
SqlConnection conn = new SqlConnection(connectionString);
conn.Credential = cred;
conn.Open();
Run Code Online (Sandbox Code Playgroud)
您还可以在连接字符串中更改密码:
SqlConnection.ChangePassword(connectionString, cred, newPassword);
Run Code Online (Sandbox Code Playgroud)
.NET内部有很多地方,为了兼容性,他们继续接受普通的字符串,然后迅速将其置于SecureString中.
这仍然存在问题:
我如何首先获得SecureString的密码?
这是一项挑战,但重点是让您考虑安全性.
有时候已经为您提供了功能.例如,WPF PasswordBox控件可以直接将输入的密码作为SecureString返回:
PasswordBox.SecurePassword属性
获取PasswordBox当前持有的密码作为SecureString.
这很有用,因为您曾经传递过原始字符串的所有地方,现在您的类型系统抱怨SecureString与String不兼容.在将SecureString转换回常规字符串之前,您希望尽可能长时间地使用.
转换SecureString非常简单:
如:
private static string CreateString(SecureString secureString)
{
IntPtr intPtr = IntPtr.Zero;
if (secureString == null || secureString.Length == 0)
{
return string.Empty;
}
string result;
try
{
intPtr = Marshal.SecureStringToBSTR(secureString);
result = Marshal.PtrToStringBSTR(intPtr);
}
finally
{
if (intPtr != IntPtr.Zero)
{
Marshal.ZeroFreeBSTR(intPtr);
}
}
return result;
}
Run Code Online (Sandbox Code Playgroud)
他们真的不希望你这样做.
但是如何将字符串输入SecureString?那么你需要做的是首先在String中停止使用密码.你需要把它放在其他东西上.即使是Char[]数组也会有所帮助.
那时你可以追加每个角色并在完成后擦除明文:
for (int i=0; i < PasswordArray.Length; i++)
{
password.AppendChar(PasswordArray[i]);
PasswordArray[i] = (Char)0;
}
Run Code Online (Sandbox Code Playgroud)
你需要存储在您的密码一些记忆,你可以擦拭.从那里将它加载到SecureString中.
tl; dr:SecureString的存在提供了相当于ZeroMemory的功能.
当设备被锁定时,有些人没有看到从内存中擦除用户密码的重要性,或者在他们认证后擦除内存中的击键.那些人不使用SecureString.
Joe*_*Joe 14
很少有情况可以在当前版本的Framework中明智地使用SecureString.它实际上只对与非托管API交互有用 - 您可以使用Marshal.SecureStringToGlobalAllocUnicode封送它.
一旦将它转换为System.String或从System.String转换它,你就失败了它的目的.
MSDN 示例一次从控制台输入生成SecureString一个字符,并将安全字符串传递给非托管API.这是相当复杂和不现实的.
您可能希望.NET的未来版本对SecureString有更多支持,这将使其更有用,例如:
SecureString Console.ReadLineSecure()或类似的东西将控制台输入读入SecureString,而不需要样本中的所有复杂代码.
WinForms TextBox替换,将其TextBox.Text属性存储为安全字符串,以便可以安全地输入密码.
与安全相关的API的扩展,允许密码作为SecureString传递.
如果没有上述内容,SecureString将具有有限的价值.
Jos*_*amm 12
我相信你必须做一个字符追加而不是一个平面实例化的原因是因为在后台将"密码"传递给SecureString的构造函数会将"密码"字符串放入内存中,从而破坏安全字符串的目的.
通过追加你只是将一个角色一次放入记忆中,这种记忆可能不会彼此相邻,从而使重建原始字符串变得更加困难.我可能在这里错了,但这就是我向他解释的原因.
该类的目的是防止通过内存转储或类似工具公开安全数据.
SecureString的一大优点是可以避免由于页面缓存而将数据存储到磁盘的可能性。如果您的内存中有密码,然后加载了一个大型程序或数据集,则当您的程序内存不足时,您的密码可能会写入交换文件。使用SecureString,至少数据不会以明文形式无限期地驻留在磁盘上。
我会停止使用 SecureString。看来 PG 们正在放弃对它的支持。甚至可能在将来拉它 - https://github.com/dotnet/apireviews/tree/master/2015-07-14-securestring。
我们应该在 .NET Core 中的所有平台上删除 SecureString 的加密 - 我们应该废弃 SecureString - 我们可能不应该在 .NET Core 中公开 SecureString
| 归档时间: |
|
| 查看次数: |
38016 次 |
| 最近记录: |