C#SecureString问题

Tay*_*ese 25 .net c# securestring

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

IntPtr ptr = Marshal.SecureStringToBSTR(SecureString object);
string value = Marshal.PtrToStringBSTR(ptr);
Run Code Online (Sandbox Code Playgroud)

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

Dou*_*oug 27

这是我为此专门写的课程.是完全的,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.
}
Run Code Online (Sandbox Code Playgroud)

这是班级

/// 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
    }
}
Run Code Online (Sandbox Code Playgroud)

这段代码要求你可以编译unsafe代码,但它就像一个魅力.

问候,

-Doug

  • CER用于保证分配的句柄不会意外泄露.从本质上讲,它可以防止异步异常被触发,从而导致内存泄漏.ExecuteCodeWithGuaranteedCleanup保证即使在无关的情况下也会将字符串清零,例如StackOverFlowException(如果未使用ExecuteCodeWithGuaranteedCleanup,则会泄漏StackOverflow中的安全字符串内容).有关.NET可靠性功能的详细说明,请参阅以下文章:http://msdn.microsoft.com/en-us/magazine/cc163716.aspx (3认同)

Mar*_*ers 12

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

从文章中,关键点是:

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

  • 这是一篇很好的文章,但它绝对是疯狂的 - 不仅如此,但你仍然有一段时间在内存中的字符串,在机器上快速管理员访问 - >在调试器中挂钩=感谢您的密码.任何人都可以真正看到这些的意义吗? (4认同)
  • 泰勒L:您可以使用char []代替,但您仍然需要固定它.如果您没有GC可以在垃圾收集期间重新定位它,那么您将无法将原始副本归零. (4认同)

Hen*_*man 9

只要您不使用SecureStrings,SecureStrings就是安全的.) - ;

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

只要你尽快采取将数组归零的预防措施,将它复制到char []会更安全一些.但是阵列存在于内存中一段时间​​,这是一种安全风险(违规).

不幸的是,库中的SecureStrings支持很少.与他们合作的最常见方式是一次一个字符.

编辑:

char[]阵列应该寄托,和Mark Byers公司提供了一个链接到一篇文章做同样的事情用一个固定字符串.这是一个选择问题,但字符串的风险在于它很容易被复制(将它传递给某个执行方法Trim()就足够了).

  • 您可以从Mark Byers的回答中的链接中采用第4步.但它应该是一个固定的`char []`,因为否则GC可以移动它(并保留旧的副本不受你的控制). (2认同)
  • 听起来最简单的答案就是不要使用它们.:-) (2认同)