C#SecureString问题

有没有办法在不包含安全性的情况下获得SecureString的价值? 例如,在下面的代码中,只要执行PtrToStringBSTR,字符串就不再安全,因为字符串是不可变的,垃圾收集对于字符串是不确定的。

IntPtr ptr = Marshal.SecureStringToBSTR(SecureString object); string value = Marshal.PtrToStringBSTR(ptr); 

如果有办法获取非托管BSTR字符串的char []或byte []怎么办? 这是否意味着垃圾收集更可预测(因为你将使用char []或byte []而不是字符串?这个假设是正确的,如果是这样,你将如何得到char []或byte []?

这应该可以帮助您:将SecureString密码密码连接到字符串

从文章中,关键点是:

  • 将字符串固定在内存中。
  • 使用托管指针来改变System.String。
  • 使用ExecuteCodeWithGuaranteedCleanup方法的强保证。

这是我为此专门写的课程。 它是完全的,100%防黑客? 不 – 你可以做的很少,使应用程序100%安全,但如果你需要将SecureString转换为String ,这个类就可以保护自己。

以下是您使用该课程的方式:

 using(SecureStringToStringMarshaler sm = new SecureStringToStringMarshaler(secureString)) { // Use sm.String here. While in the 'using' block, the string is accessible // but pinned in memory. When the 'using' block terminates, the string is zeroed // out for security, and garbage collected as usual. } 

这是class级

 /// Copyright (C) 2010 Douglas Day /// All rights reserved. /// MIT-licensed: http://www.opensource.org/licenses/mit-license.php using System; using System.Collections.Generic; using System.Text; using System.Security; using System.Runtime.InteropServices; using System.Runtime.CompilerServices; namespace DDay.Base { public class SecureStringToStringMarshaler : IDisposable { #region Private Fields private string _String; private SecureString _SecureString; private GCHandle _GCH; #endregion #region Public Properties public SecureString SecureString { get { return _SecureString; } set { _SecureString = value; UpdateStringValue(); } } public string String { get { return _String; } protected set { _String = value; } } #endregion #region Constructors public SecureStringToStringMarshaler() { } public SecureStringToStringMarshaler(SecureString ss) { SecureString = ss; } #endregion #region Private Methods void UpdateStringValue() { Deallocate(); unsafe { if (SecureString != null) { int length = SecureString.Length; String = new string('\0', length); _GCH = new GCHandle(); // Create a CER (Contrained Execution Region) RuntimeHelpers.PrepareConstrainedRegions(); try { } finally { // Pin our string, disallowing the garbage collector from // moving it around. _GCH = GCHandle.Alloc(String, GCHandleType.Pinned); } IntPtr stringPtr = IntPtr.Zero; RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup( delegate { // Create a CER (Contrained Execution Region) RuntimeHelpers.PrepareConstrainedRegions(); try { } finally { stringPtr = Marshal.SecureStringToBSTR(SecureString); } // Copy the SecureString content to our pinned string char* pString = (char*)stringPtr; char* pInsecureString = (char*)_GCH.AddrOfPinnedObject(); for (int index = 0; index < length; index++) { pInsecureString[index] = pString[index]; } }, delegate { if (stringPtr != IntPtr.Zero) { // Free the SecureString BSTR that was generated Marshal.ZeroFreeBSTR(stringPtr); } }, null); } } } void Deallocate() { if (_GCH.IsAllocated) { unsafe { // Determine the length of the string int length = String.Length; // Zero each character of the string. char* pInsecureString = (char*)_GCH.AddrOfPinnedObject(); for (int index = 0; index < length; index++) { pInsecureString[index] = '\0'; } // Free the handle so the garbage collector // can dispose of it properly. _GCH.Free(); } } } #endregion #region IDisposable Members public void Dispose() { Deallocate(); } #endregion } } 

此代码要求您可以编译unsafe代码,但它的作用就像一个魅力。

问候,

-Doug

只要您不使用SecureStrings,SecureStrings就是安全的。 ) – ;

你不应该做的一件事是复制到一个字符串(无论方法如何)。 该字符串是不可变的,可能会长时间保留在内存中。

只要您尽快采取将该arrays归零的预防措施,将其复制到char []会更安全一些。 但是arrays存在于内存中一段时间​​,这是一种安全风险(违规)。

不幸的是,库中的SecureStrings支持很少。 使用它们的最常见方式是一次一个字符。

编辑:

应该固定char[]数组,并且Mark Byers提供指向使用固定字符串执行相同操作的文章的链接。 这是一个选择问题,但字符串的风险是它很容易被复制(将它传递给执行Trim()某个方法就足够了)。

Mark提供的链接是您可以做的最好的,也是我的团队为解决这个问题所采取的方法(尽管我们没有考虑使用CER的复杂性)。 我有点怀疑使用固定基本上打破C#字符串不变性,但它确实有效。

使用Marshal.ZeroFreeBSTR :

编辑:是的,创建一个新的String将创建一个副本,因此您将失去对内容清理的控制。 您可以通过在不安全的上下文中强制转换IntPtr.ToPointer()返回的指针来访问char []:

 IntPtr ptr = Marshal.SecureStringToBSTR(str); unsafe { char *cp = (char*)ptr.ToPointer(); //access char[] through cp } Marshal.ZeroFreeBSTR(ptr);