Cómo manejar adecuadamente las contraseñas en C #

5

Es un hecho bien conocido que C # string es bastante inseguro, no está anclado en la RAM, el recolector de basura puede moverlo, copiarlo, dejar múltiples huellas en la RAM y la RAM se puede intercambiar y estar disponible como un archivo para leer, sin mencionar otros hechos conocidos.

Para mitigar esto, a Microsoft se le ocurrió SecureString . La cuestión es: ¿cuál es la forma correcta de usarlo?

Pido esto porque tarde o temprano tendrás que extraer la cadena interna. Y sí, SecureString nos permite escribir un char a la vez y nos da otros usos menores mientras escondemos su secreto, pero a veces necesitamos toda la cadena a la vez o algo así. Hasta ahora, todas las implementaciones que veo usan un string regular al final, con el contenido extraído y descifrado del SecureString que creo (o espero) que es evitable en algunos casos, aunque puede implicar un código complicado para moverse un .NET string .

En mi caso, uso una biblioteca para el hashing de contraseñas denominado BCrypt . Utiliza un string regular para calcular los hashes, que creo que está lejos de ser ideal. No encontré ninguna biblioteca que aceptara un SecureString directamente, así que no tengo mucha opción, pero la uso.

Actualmente ejecuto código como este:

SecureString password; // This usually comes from a PasswordBox Property
IntPtr passwordBSTR = Marshal.SecureStringToBSTR(password);

string insecurePassword = Marshal.PtrToStringBSTR(passwordBSTR);
Marshal.ZeroFreeBSTR(passwordBSTR);
passwordBSTR = default(IntPtr);
password.Clear();

// Use the insecurePassword....usually as:
bool result = BCrypt.Net.BCrypt.Verify(insecurePassword, user.Password); // This hashes the provided password and compares it with another BCrypt hash.

insecureString = string.Empty; // hoping for the GC to act now, fingers crossed.

// use result and etc...

De esta manera, la contraseña raw string se copiará varias veces para el método BCrypt y probablemente incluso más veces dentro de él.

Esto hace que surjan algunas preguntas en mi mente:

1 - ¿Son BSTR cadenas como C cadenas en el sentido de administración de memoria? ¿Están fijadas en la RAM y puedo manipularlas y borrarlas según lo crea conveniente? es más seguro usarlos en C # o interoperarlo con un código C ++ para poder eliminar muchas de mis manipulaciones .NET string (como verificar si la cadena de la contraseña es un espacio en blanco nulo o blanco o tiene la longitud correcta o tiene la contraseña deseada) fuerza)?

2 - Si la respuesta # 1 de la pregunta es "sí", entonces ¿debería invertir algo de tiempo para pasar la cadena BSTR a un código de interoperabilidad C ++ para calcular el hash y verificar?

3 - ¿Mi código posterior es correcto o me falta algo en la manipulación SecureString ?

Solo para ser claro: Mi principal intención con esta pregunta es evaluar si debo pasar todo mi código de manejo de contraseña a C ++ desde mi C # (probablemente usando C ++ / CLI o interoperabilidad) para lograr un Código más seguro que lo que C # tiene para ofrecer. Este escenario realmente me preocupa para el hashing de cadenas de contraseñas donde se crearán múltiples cadenas y se copiarán con la información secreta del usuario dispersada por toda la RAM.

Como ejemplo: podría hacer un método como:

public string SecureHash(SecureString password)

Y este método extraerá el valor SecureString y lo pasará como una cadena BSTR (u otra opción de extracción, honestamente no conozco los beneficios entre ellos) a un método de hashing C ++, por lo que podemos controlar todos los lugares donde se encuentra nuestra contraseña en la memoria.

Le pido a esto que no haga un gran trabajo refactorizando mi código y al final descubro que todo fue en vano porque estaba usando SecureStrings incorrectamente todo el tiempo y ya hay soluciones para esto, o una falsa Sentido de seguridad, como sucede a veces, ya que no sé cómo se implementan BSTR cadenas en la memoria o el otro SecureStrings opciones de extracción (Unicode, ANSI y etc.)

    
pregunta mFeinstein 20.09.2016 - 01:37
fuente

1 respuesta

1

Todo depende de lo que quieras hacer.

Responde a la primera parte de tu publicación:

Hay implementaciones de .net de cadenas seguras en lo siguiente: 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) System.Diagnostics.ProcessStartInfo :: Password es una propiedad SecureString y finalmente X509Certificate2 toma un SecureString para la contraseña.

Responde a la segunda parte de tu publicación:

Si desea obtener más información sobre las funciones internas de hash, BCrypt / BCryptPrimatives / PBKDF2 generalmente se consideran compatibles con FIPS 140-2 (un estándar del gobierno), específicamente porque manejan con cuidado el hashing y las contraseñas en el disco y en la memoria.

Si realmente quieres entrar en el grano nítido (y parece que lo haces ...) Ve aquí: enlace

Hay muchos detalles sobre cómo funciona esto en ese PDF, perdón por el enlace, es un tema demasiado grande para cubrirlo en una sola publicación.

    
respondido por el mumbles 20.09.2016 - 05:15
fuente

Lea otras preguntas en las etiquetas