¿Cuándo necesitaría un SecureString en .NET?

Estoy tratando de asimilar el propósito de SecureString de .NET. Desde MSDN:

Una instancia de la clase System.String es inmutable y, cuando ya no se necesita, no se puede progtwigr programáticamente para la recolección de elementos no utilizados. es decir, la instancia es de solo lectura después de que se crea y no es posible predecir cuándo se eliminará la instancia de la memoria de la computadora. En consecuencia, si un objeto String contiene información confidencial, como una contraseña, número de tarjeta de crédito o datos personales, existe el riesgo de que la información se revele después de ser utilizada porque su aplicación no puede eliminar los datos de la memoria de la computadora.

Un objeto SecureString es similar a un objeto String en que tiene un valor de texto. Sin embargo, el valor de un objeto SecureString se cifra automáticamente, se puede modificar hasta que la aplicación lo marque como de solo lectura y se puede eliminar de la memoria de la computadora con la aplicación o el recolector de elementos no utilizados de .NET Framework.

El valor de una instancia de SecureString se cifra automáticamente cuando la instancia se inicializa o cuando se modifica el valor. Su aplicación puede hacer que la instancia sea inmutable y evitar nuevas modificaciones invocando el método MakeReadOnly.

¿Es la encriptación automática la gran recompensa?

Y por qué no puedo simplemente decir:

SecureString password = new SecureString("password"); 

en lugar de

 SecureString pass = new SecureString(); foreach (char c in "password".ToCharArray()) pass.AppendChar(c); 

¿Qué aspecto de SecureString me estoy perdiendo?

Algunas partes del marco que actualmente usan SecureString :

  • El control System.Windows.Controls.PasswordBox de WPF mantiene la contraseña como SecureString internamente (expuesta como una copia a través de PasswordBox::SecurePassword )
  • La propiedad System.Diagnostics.ProcessStartInfo::Password es una SecureString
  • El constructor de X509Certificate2 toma una SecureString para la contraseña

El objective principal es reducir la superficie de ataque, en lugar de eliminarla. SecureStrings están “inmovilizados” en la memoria RAM para que el recolector de basura no lo mueva ni haga copias de él. También se asegura de que el texto plano no se escriba en el archivo Swap o en los volcados del núcleo. Sin embargo, el cifrado es más parecido a la ofuscación y no detendrá a un pirata informático determinado, que podría encontrar la clave simétrica utilizada para encriptarlo y descifrarlo.

Como han dicho otros, la razón por la que tiene que crear un SecureString carácter por carácter es debido a la primera falla obvia de hacer lo contrario: presumiblemente ya tiene el valor secreto como una cadena simple, entonces, ¿cuál es el punto?

SecureString s son el primer paso para resolver un problema de Chicken-and-Egg, por lo que aunque la mayoría de los escenarios actuales requieren volver a convertirlos en cadenas normales para usarlos en absoluto, su existencia en el framework ahora significa un mejor soporte para ellos en el futuro, al menos hasta el punto en que su progtwig no tiene que ser el eslabón débil.

Muchas respuestas geniales aquí hay una breve sinopsis de lo que se ha discutido.

Microsoft ha implementado la clase SecureString en un esfuerzo por proporcionar una mejor seguridad con información confidencial (como tarjetas de crédito, contraseñas, etc.). Proporciona automáticamente:

  • cifrado (en caso de volcados de memoria o almacenamiento en caché de páginas)
  • fijación en memoria
  • capacidad de marcar como de solo lectura (para evitar modificaciones adicionales)
  • construcción segura al NO permitir que se pase una cuerda constante en

Actualmente, SecureString tiene un uso limitado pero espera una mejor adopción en el futuro.

En función de esta información, el constructor de SecureString no debería simplemente tomar una cadena y dividirla en una matriz char ya que la cadena explicada derrota el propósito de SecureString.

Información adicional:

  • Una publicación del blog .NET Security habla de casi lo mismo que aquí.
  • Y otra que lo vuelve a visitar y menciona una herramienta que PUEDE volcar los contenidos de SecureString.

Editar: Me resultó difícil elegir la mejor respuesta, ya que hay buena información en muchos; lástima que no hay opciones de respuesta asistida.

Hay muy pocos escenarios en los que pueda usar SecureString en la versión actual del Framework. En realidad, solo es útil para interactuar con API no administradas: puede ordenarla usando Marshal.SecureStringToGlobalAllocUnicode.

Tan pronto como lo convierta a / desde un System.String, habrá vencido su propósito.

El ejemplo de MSDN genera SecureString un carácter a la vez desde la entrada de la consola y pasa la cadena segura a una API no administrada. Es bastante intrincado y poco realista.

Puede esperar que las versiones futuras de .NET tengan más soporte para SecureString que lo hará más útil, por ejemplo:

  • SecureString Console.ReadLineSecure () o similar para leer la entrada de la consola en una SecureString sin todo el código intrincado en la muestra.

  • Reemplazo de WinForms TextBox que almacena su propiedad TextBox.Text como una cadena segura para que las contraseñas se puedan ingresar de forma segura.

  • Extensiones a las API relacionadas con la seguridad para permitir que las contraseñas pasen como SecureString.

Sin lo anterior, SecureString tendrá un valor limitado.

Creo que la razón por la que hay que agregar el carácter en lugar de una instanciación plana es porque, en el fondo, pasar “contraseña” al constructor de SecureString pone esa cadena de “contraseña” en la memoria anulando el propósito de la cadena segura.

Al agregar, solo está colocando un carácter a la vez en la memoria, que probablemente no estará adyacente físicamente, por lo que es mucho más difícil reconstruir la cadena original. Podría estar equivocado aquí, pero así fue como me lo explicaron.

El objective de la clase es evitar la exposición de datos seguros mediante un volcado de memoria o una herramienta similar.

MS descubrió que en determinadas instancias en las que el servidor (el del escritorio, lo que sea) se bloqueaba, había momentos en que el entorno de ejecución hacía un volcado de memoria que exponía el contenido de lo que estaba en la memoria. Secure String lo cifra en la memoria para evitar que el atacante pueda recuperar el contenido de la cadena.

Respuesta corta

por qué no puedo solo decir:

 SecureString password = new SecureString("password"); 

Porque ahora tienes una password en la memoria; sin forma de borrarlo, que es exactamente el punto de SecureString .

Respuesta larga

La razón por la que SecureString existe es porque no puede usar ZeroMemory para borrar los datos confidenciales cuando haya terminado con ellos. Existe para resolver un problema que existe debido a la CLR.

En una aplicación nativa normal llamaría SecureZeroMemory :

Llena un bloque de memoria con ceros.

Nota : SecureZeroMemory es idéntico a ZeroMemory , excepto que el comstackdor no lo optimizará.

El problema es que no puede llamar a ZeroMemory o SecureZeroMemory dentro de .NET. Y en .NET las cadenas son inmutables; ni siquiera puede sobrescribir el contenido de la cadena como lo puede hacer en otros idiomas:

 //Wipe out the password for (int i=0; i 

¿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 terminamos?

La única forma en que se puede hacer es colocar la cadena en algún bloque de memoria nativo , donde luego puede llamar a ZeroMemory . Un objeto de memoria nativo como:

  • un BSTR
  • un HGLOBAL
  • CoTaskMem memoria no administrada

SecureString devuelve la capacidad perdida

En .NET, las cadenas no pueden borrarse cuando hayas terminado con ellas:

  • ellos son inmutables; no puedes sobreescribir sus contenidos
  • no puedes Dispose de ellos
  • su limpieza está a merced del recolector de basura

SecureString existe como una forma de evitar la seguridad de las cadenas y poder garantizar su limpieza cuando sea necesario.

Usted hizo la pregunta:

por qué no puedo solo decir:

 SecureString password = new SecureString("password"); 

Porque ahora tienes una password en la memoria; sin forma de borrarlo Está atrapado allí hasta que el CLR decide volver a usar 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 usa la API de protección de datos para almacenar la cadena cifrada en la memoria; De esta manera, la cadena no existirá en los archivos de intercambio, los volcados de emergencia o incluso en la ventana de variables locales con un colega que revise su caso.

¿Cómo leo la contraseña?

Entonces está la pregunta: ¿cómo interactúo con la cadena? Absolutamente no quieres un método como:

 String connectionString = secureConnectionString.ToString() 

porque ahora has vuelto al punto de partida, una contraseña de la que no puedes deshacerte. Desea obligar a los desarrolladores a manejar correctamente la cadena sensible, para que pueda borrarse de la memoria.

Es por eso que .NET proporciona tres útiles funciones de ayuda para ordenar un SecureString en una memoria no administrada:

  • SecureStringToBSTR (liberado con ZeroFreeCoTaskMemUnicode )
  • SecureStringToCoTaskMemUnicode (liberado con ZeroFreeCoTaskMemUnicode )
  • SecureStringToGlobalAllocUnicode (liberado con ZeroFreeGlobalAllocUnicode )

Convierte la cadena en una burbuja de memoria no administrada, la maneja y luego la limpia de nuevo.

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, y luego dan vuelta rápidamente y lo ponen 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 hacerte pensar sobre la seguridad.

Algunas veces la funcionalidad ya está provista para usted. Por ejemplo, el control WPF PasswordBox puede devolverle la contraseña ingresada como SecureString directamente:

Propiedad PasswordBox.SecurePassword

Obtiene la contraseña que actualmente tiene el PasswordBox como SecureString .

Esto es útil porque en todos los lugares donde solía pasar una cadena sin formato, ahora tiene el sistema de tipo que se queja de que SecureString es incompatible con String. Desea ir el mayor tiempo posible antes de tener que volver a convertir su SecureString 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; } 

Ellos realmente no quieren que lo hagas.

Pero, ¿cómo obtengo una cadena en un SecureString? Bueno, lo que tienes que hacer es dejar de tener una contraseña en una cadena en primer lugar. Necesitabas tenerlo en otra cosa. Incluso una matriz Char[] sería útil.

Ahí es cuando puedes agregar cada carácter y borrar el texto plano cuando hayas 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. Encuéntralo en SecureString desde allí.


tl; dr: SecureString existe para proporcionar el equivalente de ZeroMemory .

Algunas personas no ven el sentido de borrar la contraseña del usuario de la memoria cuando el dispositivo está bloqueado , o de borrar las pulsaciones de teclas de la memoria después de que se hayan autenticado . Esas personas no usan SecureString.

Bueno, como dice la descripción, el valor se almacena encriptado, lo que significa que un volcado de memoria de su proceso no revelará el valor de la cadena (sin un trabajo bastante serio).

La razón por la que no puede simplemente construir un SecureString a partir de una cadena constante es porque entonces tendría una versión no encriptada de la cadena en la memoria. Limitarlo a crear la cuerda en piezas reduce el riesgo de tener toda la cuerda en la memoria a la vez.

Uno de los grandes beneficios de SecureString es que se supone que evita la posibilidad de que sus datos se almacenen en el disco debido al almacenamiento en caché de la página. Si tiene una contraseña en la memoria y luego carga un gran progtwig o conjunto de datos, su contraseña puede escribirse en el archivo de intercambio a medida que su progtwig sale de la memoria. Con SecureString, al menos los datos no se quedarán indefinidamente en su disco en texto claro.

Supongo que es porque la cadena está destinada a ser segura, es decir, un hacker no debería poder leerla. Si lo inicializa con una cadena, el hacker podría leer la cadena original.

Dejaría de usar SecureString. Parece que los chicos de PG están perdiendo apoyo. Posiblemente incluso lo tire en el futuro – https://github.com/dotnet/apireviews/tree/master/2015-07-14-securestring .

Deberíamos eliminar el cifrado de SecureString en todas las plataformas en .NET Core. Debemos obsoletos SecureString. Probablemente no deberíamos exponer SecureString en .NET Core.

Otro caso de uso es cuando trabajas con aplicaciones de pago (POS) y simplemente no puedes usar estructuras de datos inmutables para almacenar datos confidenciales porque eres un desarrollador cuidadoso. Por ejemplo: si voy a almacenar los datos confidenciales de la tarjeta o metadatos de autorización en una cadena inmutable, siempre habrá el caso cuando estos datos estarán disponibles en la memoria por una cantidad significativa de tiempo después de que fue descartado. No puedo simplemente sobrescribirlo. Otra gran ventaja es que esos datos confidenciales se mantienen cifrados en la memoria.