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);