2010-02-16 7 views
8

Tengo un programa que usa System.DirectoryServices.AccountManagement.PrincipalContext para verificar que la información que un usuario ingresó en una pantalla de configuración es un usuario válido en el dominio (la computadora no está en el dominio) y hacer algunas operaciones en los usuarios del dominio. El problema es que no quiero que el usuario tenga que ingresar su contraseña cada vez que ejecuta el programa, así que quiero guardarlo, pero no me siento cómodo almacenando la contraseña como texto sin formato en su archivo app.config. PrincipalContext necesita una contraseña de texto sin formato, por lo que no puedo hacer un hash salado ya que todo el mundo lo recomienda para el almacenamiento de contraseñas.Qué hacer cuando no puede guardar una contraseña como hash

Esto es lo que hice

const byte[] mySalt = //It's a secret to everybody. 
[global::System.Configuration.UserScopedSettingAttribute()] 
public global::System.Net.NetworkCredential ServerLogin 
{ 
    get 
    { 
     var tmp = ((global::System.Net.NetworkCredential)(this["ServerLogin"])); 
     if(tmp != null) 
      tmp.Password = new System.Text.ASCIIEncoding().GetString(ProtectedData.Unprotect(Convert.FromBase64String(tmp.Password), mySalt, DataProtectionScope.CurrentUser)); 
     return tmp; 
    } 
    set 
    { 
     var tmp = value; 
     tmp.Password = Convert.ToBase64String(ProtectedData.Protect(new System.Text.ASCIIEncoding().GetBytes(tmp.Password), mySalt, DataProtectionScope.CurrentUser)); 
     this["ServerLogin"] = value; 
    } 
} 

¿Era esto lo que hay que hacer o hay una manera mejor?

EDITAR - Aquí está una versión actualizada en base a las sugerencias de todos

private MD5 md5 = MD5.Create(); 

[global::System.Configuration.UserScopedSettingAttribute()] 
public global::System.Net.NetworkCredential ServerLogin 
{ 
    get 
    { 
     var tmp = ((global::System.Net.NetworkCredential)(this["ServerLogin"])); 
     if(tmp != null) 
      tmp.Password = System.Text.Encoding.UTF8.GetString(ProtectedData.Unprotect(Convert.FromBase64String(tmp.Password), md5.ComputeHash(System.Text.Encoding.UTF8.GetBytes(tmp.UserName.ToUpper())), DataProtectionScope.CurrentUser)); 
     return tmp; 
    } 
    set 
    { 
     var tmp = value; 
     tmp.Password = Convert.ToBase64String(ProtectedData.Protect(System.Text.Encoding.UTF8.GetBytes(tmp.Password), md5.ComputeHash(System.Text.Encoding.UTF8.GetBytes(tmp.UserName.ToUpper())), DataProtectionScope.CurrentUser)); 
     this["ServerLogin"] = tmp; 
    } 
} 
+1

¿Quién y qué está tratando de defender la contraseña? – SLaks

+0

Diría que la forma "adecuada" sería mantener el boleto Kerberos, pero no sé cómo en este contexto, lo siento. – ziya

+1

@Slaks - Estoy defendiendo la contraseña de compañeros de trabajo aburridos que se han sentado en la computadora de otra persona. Solo quiero protegerme del observador casual, no de un hacker determinado. –

Respuesta

2

En lugar de escribir new System.Text.ASCIIEncoding(), debe escribir System.Text.Encoding.ASCII.

Además, recomiendo usar UTF8 en su lugar.

Aparte de eso, su código se ve bastante bien.

+0

Gracias por la sugerencia acerca de la otra forma de usar el codificador. ¿Por qué recomienda UTF8 sobre ASCII? –

+1

Para que las contraseñas puedan contener caracteres Unicode. – SLaks

+0

Gracias, lo cambiaré. –

4

Para la sal, haría una transformación en el nombre de usuario (hash it) en lugar de compartir la misma sal para todos.

Para algo como esto, también buscaría la manera de mantener viva la sesión existente durante más tiempo en lugar de guardar la contraseña para crear nuevas sesiones.

+0

La sesión está viva toda la instancia en la que se ejecuta el programa, solo necesito crear la sesión con el servidor cuando se inicia el programa, ¿o quiso decir mantener viva la sesión entre ejecuciones? –

+0

Puede utilizar un servicio u otro programa en segundo plano para mantener la sesión y mantenerla activa durante más tiempo. –

0

Me gusta el enfoque de JoelCoehoorn.

Utilice un valor exclusivo para la máquina del usuario como contraseña.

Por lo tanto, será diferente en cada deplyment;)

ACTUALIZACIÓN: Ver este tema por las ideas: How-To-Get-Unique-Machine-Signature

+0

¿Qué es lo que el mismo usuario inicia sesión en diferentes máquinas? Tiene que ser por usuario. –

+0

Hola Joel, gracias por preguntar:) Si el usuario cambia de una PC a otra, deberá ingresar sus credenciales de dominio necesariamente, antes de almacenar en la memoria caché;) – SDReyes

+0

'ProtectedData.Protect' ya es por máquina. – SLaks

Cuestiones relacionadas