Estoy tratando de entender el propósito de SecureString de .NET. De MSDN:
Una instancia de la clase System.String es inmutable y, cuando ya no se necesita, no se puede programar mediante programación para la recolección de basura; es decir, la instancia es de solo lectura después de su creación y no es posible predecir cuándo se eliminará de la memoria de la computadora. En consecuencia, si un objeto String contiene información confidencial, como una contraseña, un 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, puede modificarse hasta que su aplicación lo marque como de solo lectura y su aplicación o el recolector de basura de .NET Framework pueden eliminarlo de la memoria de la computadora.
El valor de una instancia de SecureString se cifra automáticamente cuando se inicializa la instancia o cuando se modifica el valor. Su aplicación puede hacer que la instancia sea inmutable y evitar modificaciones adicionales invocando el método MakeReadOnly.
¿El cifrado automático es la gran recompensa?
¿Y por qué no puedo simplemente decir:
SecureString password = new SecureString("password");
en vez de
SecureString pass = new SecureString();
foreach (char c in "password".ToCharArray())
pass.AppendChar(c);
¿Qué aspecto de SecureString me estoy perdiendo?
fuente
SecureString
nuevos desarrollos: github.com/dotnet/platform-compat/blob/master/docs/DE0001.mdRespuestas:
Dejaría de usar SecureString. Parece que los chicos de PG están dejando de apoyarlo. Posiblemente incluso lo tire en el futuro: https://github.com/dotnet/apireviews/tree/master/2015-07-14-securestring .
fuente
Algunas partes del marco que actualmente utilizamos
SecureString
:System.Windows.Controls.PasswordBox
control de WPF mantiene la contraseña como SecureString internamente (expuesta como una copiaPasswordBox::SecurePassword
)System.Diagnostics.ProcessStartInfo::Password
propiedad es unSecureString
X509Certificate2
toma unaSecureString
para la contraseñaEl objetivo principal es reducir la superficie de ataque, en lugar de eliminarla.
SecureStrings
están "anclados" en la RAM para que el recolector de basura no lo mueva ni haga copias de él. También se asegura de que el texto sin formato no se escriba en el archivo de intercambio o en los volcados del núcleo. Sin embargo, el cifrado se parece más a la ofuscación y no detendrá a un hacker determinado, que podría encontrar la clave simétrica utilizada para cifrarlo y descifrarlo.Como otros han dicho, la razón por la que tienes que crear un
SecureString
carácter por carácter se debe 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 huevo y gallina, por lo que, aunque la mayoría de los escenarios actuales requieren convertirlos de nuevo en cadenas regulares para usarlos, su existencia en el marco ahora significa un mejor apoyo para ellos en el futuro, al menos hasta el punto en que su programa no tiene que ser el eslabón débil.fuente
Editar : no use SecureString
La orientación actual ahora dice que la clase no debe usarse. Los detalles se pueden encontrar en este enlace: https://github.com/dotnet/platform-compat/blob/master/docs/DE0001.md
Del artículo:
DE0001: SecureString no debe usarse
Motivación
SecureString
es evitar tener secretos almacenados en la memoria del proceso como texto sin formato.SecureString
no existe como un concepto de sistema operativo.System.String
: la vida útil del búfer nativo es más corta.Recomendación
No usar
SecureString
para el nuevo código. Al portar código a .NET Core, tenga en cuenta que el contenido de la matriz no está cifrado en la memoria.El enfoque general de tratar con credenciales es evitarlas y confiar en otros medios para autenticarse, como certificados o autenticación de Windows.
Finalizar edición: Resumen original a continuación
Muchas respuestas geniales; Aquí hay una sinopsis rápida 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:
Actualmente, SecureString tiene un uso limitado, pero se espera una mejor adopción en el futuro.
Según esta información, el constructor de SecureString no solo debe tomar una cadena y dividirla en una matriz de caracteres, ya que la cadena deletreada anula el propósito de SecureString.
Información adicional:
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.
fuente
Respuesta corta
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
:Nota : SecureZeroMemory es idéntico a
ZeroMemory
, excepto que el compilador no lo optimizará.El problema es que no puedes llamar
ZeroMemory
niSecureZeroMemory
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:¿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:SecureString devuelve la habilidad perdida
En .NET, las cadenas no se pueden borrar cuando haya terminado con ellas:
Dispose
de ellosSecureString existe como una forma de pasar la seguridad de las cadenas y poder garantizar su limpieza cuando sea necesario.
Hiciste la pregunta:
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:
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 :
También puede cambiar la contraseña dentro de una Cadena de conexión:
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:
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:
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:
como en:
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 un
Char[]
matriz sería útil.Ahí es cuando puede agregar cada carácter y borrar el texto sin formato cuando haya terminado:
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.
fuente
Existen muy pocos escenarios en los que pueda utilizar de manera sensata SecureString en la versión actual de Framework. Realmente solo es útil para interactuar con API no administradas: puede ordenarlo usando Marshal.SecureStringToGlobalAllocUnicode.
Tan pronto como lo convierta a / de un System.String, ha vencido su propósito.
La muestra 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 complicado y poco realista.
Es posible que las futuras versiones 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 un SecureString sin todo el código complicado 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 se pasen como SecureString.
Sin lo anterior, SecureString tendrá un valor limitado.
fuente
Creo que la razón por la que tiene que agregar caracteres en lugar de una instanciación plana es porque en el fondo, pasar "contraseña" al constructor de SecureString coloca esa cadena de "contraseña" en la memoria, lo que anula el propósito de la cadena segura.
Al agregar, solo está poniendo un carácter a la vez en la memoria, lo que probablemente no sea adyacente físicamente, lo que hace que sea mucho más difícil reconstruir la cadena original. Podría estar equivocado aquí, pero así fue como me lo explicaron.
El propósito de la clase es evitar que los datos seguros se expongan a través de un volcado de memoria o una herramienta similar.
fuente
MS descubrió que en ciertas instancias de causar que el servidor (escritorio, lo que sea) se bloquee, hubo momentos en que el entorno de ejecución haría un volcado de memoria exponiendo el contenido de lo que hay en la memoria. Secure String lo cifra en la memoria para evitar que el atacante pueda recuperar el contenido de la cadena.
fuente
Uno de los grandes beneficios de un 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 programa o conjunto de datos, su contraseña puede escribirse en el archivo de intercambio a medida que su programa se borra de la memoria. Con SecureString, al menos los datos no se quedarán indefinidamente en su disco en texto claro.
fuente
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.
fuente
Bueno, como dice la descripción, el valor se almacena cifrado, 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 construir un SecureString a partir de una cadena constante es porque tendría una versión sin cifrar de la cadena en la memoria. Limitarlo a crear la cadena en pedazos reduce el riesgo de tener toda la cadena en la memoria a la vez.
fuente
Otro caso de uso es cuando está trabajando con aplicaciones de pago (POS) y simplemente no puede usar estructuras de datos inmutables para almacenar datos confidenciales porque es un desarrollador cuidadoso. Por ejemplo: si voy a almacenar datos confidenciales de la tarjeta o metadatos de autorización en una cadena inmutable, siempre sería el caso cuando estos datos estén disponibles en la memoria durante un período de tiempo significativo después de que se descartaron. No puedo simplemente sobrescribirlo. Otra gran ventaja es que dichos datos confidenciales se guardan en la memoria encriptada.
fuente