Respuesta corta
¿Por qué no puedo decir:
SecureString password = new SecureString("password");
Porque ahora lo tienes password
en memoria; sin forma de borrarlo, que es exactamente el punto de SecureString .
Respuesta larga
La razón por la que existe SecureString es porque no puede usar ZeroMemory para borrar datos confidenciales cuando haya terminado con ella. Existe para resolver un problema que existe debido al CLR.
En una aplicación nativa normal llamarías SecureZeroMemory
:
Llena un bloque de memoria con ceros.
Nota : SecureZeroMemory es idéntico a ZeroMemory
, excepto que el compilador no lo optimizará.
El problema es que no puedes llamar ZeroMemory
ni SecureZeroMemory
dentro de .NET. Y en .NET las cadenas son inmutables; ni siquiera puede sobrescribir el contenido de la cadena como puede hacerlo en otros idiomas:
//Wipe out the password
for (int i=0; i<password.Length; i++)
password[i] = \0;
¿Entonces que puedes hacer? ¿Cómo proporcionamos la capacidad en .NET para borrar una contraseña o número de tarjeta de crédito de la memoria cuando hayamos terminado con ella?
La única forma en que se puede hacer es colocar la cadena en algún bloque de memoria nativa , donde luego puede llamar ZeroMemory
. Un objeto de memoria nativa como:
- un BSTR
- un HGLOBAL
- Memoria no administrada de CoTaskMem
SecureString devuelve la habilidad perdida
En .NET, las cadenas no se pueden borrar cuando haya terminado con ellas:
- son inmutables; no puedes sobrescribir sus contenidos
- no puedes
Dispose
de ellos
- su limpieza está a merced del recolector de basura
SecureString existe como una forma de pasar la seguridad de las cadenas y poder garantizar su limpieza cuando sea necesario.
Hiciste la pregunta:
¿Por qué no puedo decir:
SecureString password = new SecureString("password");
Porque ahora tienes password
en memoria; sin forma de limpiarlo. Está atascado allí hasta que el CLR decida reutilizar esa memoria. Nos has devuelto a donde comenzamos; una aplicación en ejecución con una contraseña que no podemos eliminar, y donde un volcado de memoria (o Process Monitor) puede ver la contraseña.
SecureString utiliza la API de protección de datos para almacenar la cadena encriptada en la memoria; de esa manera, la cadena no existirá en archivos de intercambio, volcados por caída o incluso en la ventana de variables locales con un colega revisando su debería.
¿Como leo la contraseña?
Entonces es la pregunta: ¿cómo interactúo con la cadena? Absolutamente no quieres un método como:
String connectionString = secureConnectionString.ToString()
porque ahora estás de vuelta donde empezaste: una contraseña de la que no puedes deshacerte. Desea obligar a los desarrolladores a manejar la cadena sensible correctamente, para que pueda borrarse de la memoria.
Es por eso que .NET proporciona tres prácticas funciones de ayuda para ordenar un SecureString en una memoria no administrada:
Convierte la cadena en un blob de memoria no administrado, lo maneja y luego lo limpia nuevamente.
Algunas API aceptan SecureStrings . Por ejemplo, en ADO.net 4.5, SqlConnection.Credential toma un conjunto SqlCredential :
SqlCredential cred = new SqlCredential(userid, password); //password is SecureString
SqlConnection conn = new SqlConnection(connectionString);
conn.Credential = cred;
conn.Open();
También puede cambiar la contraseña dentro de una Cadena de conexión:
SqlConnection.ChangePassword(connectionString, cred, newPassword);
Y hay muchos lugares dentro de .NET donde continúan aceptando un String simple para fines de compatibilidad, luego rápidamente lo cambian y lo colocan en un SecureString.
¿Cómo poner texto en SecureString?
Esto todavía deja el problema:
¿Cómo obtengo una contraseña en SecureString en primer lugar?
Este es el desafío, pero el punto es hacerle pensar en seguridad.
A veces, la funcionalidad ya está disponible para usted. Por ejemplo, el control WPF PasswordBox puede devolverle la contraseña ingresada como SecureString directamente:
Obtiene la contraseña que actualmente posee PasswordBox como SecureString .
Esto es útil porque en todas partes donde solía pasar una cadena sin formato, ahora tiene el sistema de tipos quejándose de que SecureString es incompatible con String. Desea ir el mayor tiempo posible antes de tener que convertir su SecureString nuevamente en una cadena normal.
Convertir un SecureString es bastante fácil:
- SecureStringToBSTR
- PtrToStringBSTR
como en:
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;
}
Simplemente no quieren que lo hagas.
Pero, ¿cómo consigo una cadena en un SecureString? Bueno, lo que debes hacer es dejar de tener una contraseña en una cadena en primer lugar. Necesitabas tenerlo en otra cosa. Incluso unChar[]
matriz sería útil.
Ahí es cuando puede agregar cada carácter y borrar el texto sin formato cuando haya terminado:
for (int i=0; i < PasswordArray.Length; i++)
{
password.AppendChar(PasswordArray[i]);
PasswordArray[i] = (Char)0;
}
Necesita su contraseña almacenada en alguna memoria que pueda borrar. Cárguelo en SecureString desde allí.
tl; dr: SecureString existe para proporcionar el equivalente de ZeroMemory .
Algunas personas no ven el punto de borrar la contraseña del usuario de la memoria cuando un dispositivo está bloqueado , o borrar las pulsaciones de teclas de la memoria después de autenticarse . Esas personas no usan SecureString.
SecureString
nuevos desarrollos: github.com/dotnet/platform-compat/blob/master/docs/DE0001.md