Siéntete libre de corregirme si mis suposiciones están mal aquí, pero déjame explicarte por qué pregunto.
Tomado de MSDN, a SecureString
:
Representa texto que debe mantenerse confidencial. El texto está encriptado para mayor privacidad cuando se usa, y se elimina de la memoria de la computadora cuando ya no es necesario.
Entiendo esto, tiene mucho sentido almacenar una contraseña u otra información privada en un SecureString
over a System.String
, porque puedes controlar cómo y cuándo se almacena realmente en la memoria, porque a 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.
Sin embargo, en el caso de una aplicación GUI (por ejemplo, un cliente ssh), el SecureString
debe construirse a partir de a System.String
. Todos los controles de texto usan una cadena como su tipo de datos subyacente .
Entonces, esto significa que cada vez que el usuario presiona una tecla, la cadena anterior que estaba allí se descarta y se crea una nueva cadena para representar cuál es el valor dentro del cuadro de texto, incluso si se usa una máscara de contraseña. Y no podemos controlar cuándo o si alguno de esos valores se descarta de la memoria .
Ahora es el momento de iniciar sesión en el servidor. ¿Adivina qué? Debe pasar una cadena por la conexión para la autenticación . Así que vamos a convertir nuestro SecureString
en un System.String
... y ahora tenemos una cadena en el montón sin forma de forzarlo a pasar por la recolección de basura (o escribir 0 en su búfer).
Mi punto es : no importa lo que haces, en algún lugar a lo largo de la línea, que SecureString
se va a convertir en una System.String
, lo que significa que al menos existe en el montón en algún momento (sin ninguna garantía de recolección de basura).
Mi punto no es : si hay formas de eludir el envío de una cadena a una conexión ssh, o evitar que un control almacene una cadena (haga un control personalizado). Para esta pregunta, puede reemplazar "conexión ssh" con "formulario de inicio de sesión", "formulario de registro", "formulario de pago", "formulario de alimentos que alimentaría a su cachorro pero no a sus hijos", etc.
- Entonces, ¿en qué momento el uso de a se
SecureString
vuelve realmente práctico? - ¿Alguna vez vale la pena el tiempo de desarrollo adicional para erradicar por completo el uso de un
System.String
objeto? - ¿El objetivo
SecureString
es simplemente reducir la cantidad de tiempo que aSystem.String
está en el montón (reduciendo el riesgo de pasar a un archivo de intercambio físico)? - Si un atacante ya tiene los medios para una inspección de montón, lo más probable es que (A) ya tenga los medios para leer las pulsaciones de teclas, o (B) ya tenga físicamente la máquina ... Así que usar un
SecureString
impedimento para que llegue datos de todos modos? - ¿Es esto simplemente "seguridad a través de la oscuridad"?
Lo siento si estoy planteando las preguntas demasiado, la curiosidad me ganó. No dude en responder cualquiera o todas mis preguntas (o dígame que mis suposiciones están completamente equivocadas). :)
SecureString
no es realmente una cadena segura. Es simplemente una forma de disminuir el intervalo de tiempo en el que alguien puede inspeccionar su memoria y obtener con éxito los datos confidenciales. Esto no es a prueba de balas y no estaba destinado a serlo. Pero los puntos que estás planteando son muy válidos. Relacionado: stackoverflow.com/questions/14449579/…Respuestas:
En realidad, hay usos muy prácticos de
SecureString
.¿Sabes cuántas veces he visto tales escenarios? (la respuesta es: ¡muchas!):
RedGate
software que podía capturar el "valor" de las variables locales en caso de excepciones, increíblemente útil. Sin embargo, puedo imaginar que registrará "contraseñas de cadena" accidentalmente.¿Sabes cómo evitar todos estos problemas?
SecureString
. En general, se asegura de que no cometas errores tontos como tales. ¿Cómo lo evita? Al asegurarse de que la contraseña esté encriptada en la memoria no administrada y que solo se pueda acceder al valor real cuando esté 90% seguro de lo que está haciendo.En el sentido,
SecureString
funciona con bastante facilidad:1) Todo está encriptado
2) llamadas de usuario
AppendChar
3) Descifra todo en MEMORIA NO MANEJADA y agrega el personaje
4) Cifrar todo de nuevo en MEMORIA NO MANEJADA.
¿Qué pasa si el usuario tiene acceso a su computadora? ¿Podría un virus tener acceso a todo el
SecureStrings
? Si. Todo lo que necesita hacer es conectarseRtlEncryptMemory
cuando se descifre la memoria, obtendrá la ubicación de la dirección de memoria no cifrada y la leerá. Voila! De hecho, podría crear un virus que constantemente analizará el usoSecureString
y registrará todas las actividades con él. No estoy diciendo que será una tarea fácil, pero se puede hacer. Como puede ver, la "potencia" deSecureString
desaparece por completo una vez que hay un usuario / virus en su sistema.Tienes algunos puntos en tu publicación. Claro, si usa algunos de los controles de la interfaz de usuario que contienen una "contraseña de cadena" internamente, usar actual
SecureString
no es tan útil. Aunque, aún así, puede proteger contra alguna estupidez que he enumerado anteriormente.Además, como otros han señalado, WPF admite PasswordBox, que utiliza
SecureString
internamente a través de su propiedad SecurePassword .La conclusión es; si tiene datos confidenciales (contraseñas, tarjetas de crédito, ..), use
SecureString
. Esto es lo que C # Framework está siguiendo. Por ejemplo, laNetworkCredential
clase almacena la contraseña comoSecureString
. Si observa esto , puede ver más de 80 usos diferentes en .NET framework deSecureString
.Hay muchos casos en los que tiene que convertir
SecureString
a cadena, porque algunas API lo esperan.El problema habitual es:
Has planteado un buen punto: ¿qué sucede cuando
SecureString
se convierte astring
? Esto solo puede suceder debido al primer punto. Por ejemplo, la API no sabe que son datos confidenciales. Personalmente no he visto que eso suceda. Sacar una cadena de SecureString no es tan simple.No es simple por una simple razón ; nunca tuvo la intención de permitir que el usuario convirtiera SecureString en cadena, como usted dijo: GC se activará. Si se ve haciendo eso, debe retroceder y preguntarse: ¿por qué estoy haciendo esto, o realmente necesito? ¿esto por que?
Hay un caso interesante que vi. A saber, la función WinApi LogonUser toma LPTSTR como contraseña, lo que significa que debe llamar
SecureStringToGlobalAllocUnicode
. Básicamente, eso le proporciona una contraseña no cifrada que vive en la memoria no administrada. Debe deshacerse de eso tan pronto como termine:Siempre puede extender la
SecureString
clase con un método de extensión, comoToEncryptedString(__SERVER__PUBLIC_KEY)
, que le proporciona unastring
instancia deSecureString
que está cifrada con la clave pública del servidor. Solo el servidor puede descifrarlo. Problema resuelto: Garbage Collection nunca verá la cadena "original", ya que nunca la expondrá en la memoria administrada. Esto es exactamente lo que se está haciendo enPSRemotingCryptoHelper
(EncryptSecureStringCore(SecureString secureString)
).Y como algo muy relacionado: Mono SecureString no cifra en absoluto . La implementación se ha comentado porque ... espere ... "De alguna manera causa la rotura de la prueba de la unidad" , lo que me lleva a mi último punto:
SecureString
no es compatible en todas partes. Si la plataforma / arquitectura no es compatibleSecureString
, obtendrá una excepción. Hay una lista de plataformas compatibles con la documentación.fuente
SecureString
sería mucho más práctico si hubiera un mecanismo para acceder a los caracteres individuales de los mismos. La eficiencia para tal mecanismo podría mejorarse teniendo un tipo de estructuraSecureStringTempBuffer
sin ningún miembro público, que podría pasarseref
alSecureString
método de "leer un carácter" [si el cifrado / descifrado se procesa en fragmentos de 8 caracteres, dicha estructura podría contener datos para 8 caracteres y la ubicación del primero de esos caracteres dentro deSecureString
].SecureString
, debe usarse en toda la pila.EngineSettings
en su método de extensión?SecureString
no debe usarse para un nuevo desarrollo ?Hay pocos problemas en sus suposiciones.
En primer lugar, la clase SecureString no tiene un constructor de cadenas. Para crear uno, asigna un objeto y luego agrega los caracteres.
En el caso de una GUI o una consola, puede pasar fácilmente cada tecla presionada a una cadena segura.
La clase está diseñada de manera que no puede, por error, acceder al valor almacenado. Esto significa que no puede obtenerla
string
como contraseña directamente de ella.Entonces, para usarlo, por ejemplo, para autenticarse a través de la web, deberá usar clases adecuadas que también sean seguras.
En el marco .NET tiene algunas clases que pueden usar SecureString
(más)
Para concluir, la clase SecureString puede ser útil, pero requiere más atención por parte del desarrollador.
Todo esto, con ejemplos, está bien descrito en la documentación de SecureString de MSDN
fuente
SecureString
través de la red sin serializarlo en unstring
? Creo que el punto de OP de la pregunta es que llega un momento en el que quieres usar realmente el valor que se mantiene de forma segura en unSecureString
, lo que significa que tienes que sacarlo de allí, y ya no es seguro. En toda la biblioteca de clases de Framework, prácticamente no hay métodos que acepten unaSecureString
entrada directamente (por lo que puedo ver), entonces, ¿cuál es el punto de mantener un valor dentro de aSecureString
en primer lugar?char[]
y enviando cada uno achar
través de un zócalo, sin crear objetos de recolección de basura en el proceso.Un SecureString es útil si:
Lo construye carácter por carácter (por ejemplo, desde la entrada de la consola) o lo obtiene de una API no administrada
Lo usa pasándolo a una API no administrada (SecureStringToBSTR).
Si alguna vez lo convierte en una cadena administrada, ha vencido su propósito.
ACTUALIZAR en respuesta al comentario
Después de que se haya convertido a un BSTR, el componente no administrado que consume el BSTR puede poner a cero la memoria. La memoria no administrada es más segura en el sentido de que se puede restablecer de esta manera.
Sin embargo, hay muy pocas API en .NET Framework que admitan SecureString, por lo que tiene razón al decir que hoy tiene un valor muy limitado.
El caso de uso principal que vería es en una aplicación cliente que requiere que el usuario ingrese un código o contraseña altamente confidenciales. La entrada del usuario podría usarse carácter por carácter para construir un SecureString, luego podría pasar a una API no administrada, que pone a cero el BSTR que recibe después de usarlo. Cualquier volcado de memoria posterior no contendrá la cadena sensible.
En una aplicación de servidor es difícil ver dónde sería útil.
ACTUALIZACIÓN 2
Un ejemplo de una API .NET que acepta un SecureString es este constructor para la clase X509Certificate . Si espelta con ILSpy o similar, verá que SecureString se convierte internamente en un búfer no administrado (
Marshal.SecureStringToGlobalAllocUnicode
), que luego se pone a cero cuando termina con (Marshal.ZeroFreeGlobalAllocUnicode
).fuente
SecureString
entrada, ¿cuál sería su uso? Siempre tendrías que volver a convertirstring
tarde o temprano (oBSTR
como mencionas, lo que no parece más seguro). Entonces, ¿por qué molestarseSecureString
en absoluto?Microsoft no recomienda usar
SecureString
para códigos más nuevos.De la documentación de la clase SecureString :
Que recomienda:
fuente
Como ha identificado correctamente,
SecureString
ofrece una ventaja específica sobrestring
: el borrado determinista. Hay dos problemas con este hecho:SecureString
. Esto significa que debe tener cuidado de no crear nunca unstring
búfer inmutable administrado por GC o cualquier otro búfer que almacene la información confidencial (o tendrá que hacer un seguimiento de eso también). En la práctica, esto no siempre es fácil de lograr, porque muchas API solo ofrecen una forma de trabajarstring
, noSecureString
. E incluso si logras hacer todo bien ...SecureString
protege contra tipos de ataque muy específicos (y para algunos de ellos, ni siquiera es tan confiable). Por ejemplo,SecureString
le permite reducir la ventana de tiempo en la que un atacante puede volcar la memoria de su proceso y extraer con éxito la información confidencial (nuevamente, como señaló correctamente), pero con la esperanza de que la ventana sea demasiado pequeña para que el atacante pueda tomar una instantánea de su memoria no se considera seguridad en absoluto.Entonces, ¿cuándo deberías usarlo? Solo cuando trabajas con algo que puede permitirte trabajar
SecureString
para todas tus necesidades e incluso entonces debes tener en cuenta que esto es seguro solo en circunstancias específicas.fuente
El texto a continuación se copia del analizador de código estático HP Fortify
Resumen: El método PassString () en PassGenerator.cs almacena datos confidenciales de manera insegura (es decir, en cadena), lo que permite extraer los datos mediante la inspección del montón.
Explicación: Los datos confidenciales (como contraseñas, números de seguridad social, números de tarjetas de crédito, etc.) almacenados en la memoria pueden filtrarse si se almacenan en un objeto String administrado. Los objetos de cadena no están anclados, por lo que el recolector de basura puede reubicar estos objetos a voluntad y dejar varias copias en la memoria. Estos objetos no están encriptados de manera predeterminada, por lo que cualquiera que pueda leer la memoria del proceso podrá ver el contenido. Además, si la memoria del proceso se intercambia en el disco, los contenidos no cifrados de la cadena se escribirán en un archivo de intercambio. Por último, dado que los objetos String son inmutables, el recolector de basura CLR solo puede eliminar el valor de un String de la memoria. No es necesario que el recolector de basura se ejecute a menos que el CLR tenga poca memoria, por lo que no hay garantía de cuándo tendrá lugar la recolección de basura.
Recomendaciones: en lugar de almacenar datos confidenciales en objetos como cadenas, almacénelos en un objeto SecureString. Cada objeto almacena su contenido en un formato cifrado en la memoria en todo momento.
fuente
Me gustaría abordar este punto:
Un atacante puede no tener acceso completo a la computadora y la aplicación, pero puede tener medios para acceder a algunas partes de la memoria del proceso. Generalmente es causado por errores como desbordamientos del búfer cuando la entrada especialmente construida puede hacer que la aplicación exponga o sobrescriba alguna parte de la memoria.
HeartBleed perdiendo memoria
Tome Heartbleed por ejemplo. Las solicitudes especialmente construidas pueden hacer que el código exponga partes aleatorias de la memoria del proceso al atacante. Un atacante puede extraer certificados SSL de la memoria, sin embargo, lo único que necesita es usar una solicitud con formato incorrecto.
En el mundo del código administrado, los desbordamientos del búfer se convierten en un problema con mucha menos frecuencia. Y en el caso de WinForms, los datos ya están almacenados de manera insegura y no puede hacer nada al respecto. Esto hace que la protección sea
SecureString
prácticamente inútil.Sin embargo, la GUI se puede programar para usar
SecureString
, y en tal caso puede valer la pena reducir la ventana de disponibilidad de contraseña en la memoria. Por ejemplo, PasswordBox.SecurePassword de WPF es de tipoSecureString
.fuente
Hace algún tiempo tuve que crear una interfaz ac # contra una pasarela de pago de tarjeta de crédito Java y uno necesitaba un cifrado de clave de comunicaciones seguro compatible. Como la implementación de Java fue bastante específica y tuve que trabajar con los datos protegidos de una manera determinada.
Encontré que este diseño es bastante fácil de usar y más fácil que trabajar con SecureString ... para aquellos que les gusta usar ... siéntanse libres, sin restricciones legales :-). Tenga en cuenta que estas clases son internas, es posible que deba hacerlas públicas.
fuente