c# .net securestring

C#SecureString pregunta



.net (5)

Aquí hay una clase que he escrito especialmente para este propósito. ¿Es completamente, 100% a prueba de hackers? No, es muy poco lo que puede hacer para que una aplicación sea 100% segura, pero esta clase va tan lejos como puede para protegerse si necesita convertir un SecureString en un String .

Así es como usas la clase:

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. }

Aqui esta la clase

/// 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 } }

Este código requiere que pueda compilar código unsafe , pero funciona como un encanto.

Saludos,

-Doug

¿Hay alguna manera de obtener el valor de un SecureString sin incluir la seguridad? Por ejemplo, en el código a continuación, tan pronto como lo hace PtrToStringBSTR, la cadena ya no es segura porque las cadenas son inmutables y la recolección de basura no es determinista para las cadenas.

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

¿Qué pasaría si hubiera una forma de obtener un char [] o un byte [] de la cadena BSTR no administrada? ¿Eso significa que la recolección de basura es más predecible (ya que utilizaría un char [] o un byte [] en lugar de una cadena? ¿Es correcto este supuesto, y si es así, cómo recuperaría el char [] o el byte []?


El enlace que Mark proporcionó es sobre lo mejor que puede hacer, y es el enfoque que mi equipo ha adoptado para abordar este problema (aunque no fuimos a la complejidad de usar los CER). Tenía algunas dudas sobre el uso de la fijación para romper esencialmente la inmutabilidad de la cadena C #, pero funciona.


Esto debería ayudarlo a usted: Acercar las contraseñas SecureString a la cadena

Del artículo, los puntos clave son:

  • Pin la cadena en la memoria.
  • Utilice punteros gestionados para mutar el System.String.
  • Utilice las garantías sólidas del método ExecuteCodeWithGuaranteedCleanup.

Los SecureStrings solo son seguros mientras no los uses. ) -;

Lo 1 que no debes hacer es copiar en una cadena (independientemente del método). La cadena es inmutable y potencialmente puede permanecer en la memoria durante mucho tiempo.

Copiarlo a un char [] es un poco más seguro siempre y cuando se tome la precaución de poner a cero esa matriz lo antes posible. Pero la matriz está presente en la memoria por algún tiempo y eso es un riesgo de seguridad (incumplimiento).

Desafortunadamente, hay muy poco soporte para SecureStrings en la biblioteca. La forma más común de trabajar con ellos es una char a la vez.

Editar:

la matriz char[] debe estar anclada, y Mark Byers proporciona un enlace a un artículo que hace lo mismo con una cadena anclada. Es una cuestión de elección, pero el riesgo de la cadena es que es muy fácil copiarla (pasarla a algún método que realice un Trim() sería suficiente).


Utilice Marshal.ZeroFreeBSTR :

EDITAR: Sí, crear una nueva Cadena creará una copia, por lo que perderá el control sobre la limpieza de los contenidos. Puede acceder al char [] lanzando el puntero devuelto por IntPtr.ToPointer () en un contexto inseguro:

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