password c# wpf security mvvm passwordbox

c# - PasswordBox y MVVM



passwordbox wpf text (4)

Tenemos el siguiente escenario:

  1. Interfaz de usuario MVVM donde un usuario puede colocar su contraseña (en realidad un PasswordBox )
  2. Servidor que hará algún trabajo.
  3. El servidor se conecta a alguna base de datos que requiere autenticación

Y ya leí esta pregunta en PasswordBox en MVVM

¡Pero no hay respuesta sobre cómo hacerlo! Sólo un montón más de "nunca hacer eso".

¿Cuál es la forma correcta de pasar una contraseña? ¿Cómo resolver los problemas de seguridad?

No hay una forma adecuada de Binding al PasswordBox y la contraseña no se almacenará en algún lugar, está bien.

Entonces, ¿cuál es la forma MVVM de hacer tales cosas?

Incluso si el patrón está roto, ¿hay una buena manera de lograr tales cosas?

Thought of a Func<string> para recuperarlo, pero sin Binding esto causará un desastre ...

Actualizar Igual para inicializar el PasswordBox desde un almacén de contraseña (con suerte cifrado). ¿No es eso romper el patrón MVVM? El usuario no desea ingresar la contraseña cada vez que inicia la aplicación o desea trabajar con la base de datos que creo.


Dejando ese artículo a un lado, hay algunas otras publicaciones relacionadas con esta pregunta en particular. Puede lograr el enlace utilizando propiedades adjuntas. Por favor mira:

  1. Creo que esta pregunta es un duplicado de enlace de PasswordBox
  2. La publicación anterior apunta a - http://www.wpftutorial.net/PasswordBox.html

Personalmente, solo paso el control PasswordBox completo a mi LoginCommand

Sé que rompe MVVM porque la capa ViewModel ahora hace referencia a un objeto específico de Vista, pero creo que en este caso específico está bien.

Entonces podría tener XAML que se parece a esto:

<Button Content="Login" Command="{Binding LoginCommand}" CommandParameter="{Binding ElementName=MyPasswordBox}" />

Y un LoginCommand que hace algo como esto:

private void Login(object obj) { PasswordBox pwBox = obj as PasswordBox; SomeBlackBoxClass.ValidatePassword(UserName, pwBox.Password); }

Supongo que también podría ejecutar algún tipo de algoritmo de cifrado en el valor y comparar el hash de ese valor con el hash de la contraseña del usuario también.

private void Login(object obj) { PasswordBox pwBox = obj as PasswordBox; var encryptedPassword = SomeLibrary.EncryptValue(pwBox.Password, someKey); if (encryptedPassword == User.EncryptedPassword) // Success }

No soy un experto en el control o la seguridad de PasswordBox , pero sí sé que no desea almacenar la contraseña del usuario en texto sin formato en la memoria de su aplicación.

(Técnicamente, se almacena como texto sin formato en PasswordBox.Password : puede usar algo como Snoop para verificar esto si lo desea). Sin embargo, normalmente PasswordBox no existe por más tiempo del que el usuario inicia sesión, y la "contraseña" real es solo el texto ingresado por el usuario, que puede o no ser correcto. Un keylogger podría obtener la misma información.)


Resolví este problema creando un UserControl que expone una propiedad de dependencia SecureString a la que se puede vincular. Este método mantiene la contraseña en un SecureString en todo momento y no "rompe" MVVM.

Control de usuario

XAML

<UserControl x:Class="Example.PasswordUserControl" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="300"> <Grid> <PasswordBox Name="PasswordBox" /> </Grid> </UserControl>

CS

public partial class PasswordUserControl : UserControl { public SecureString Password { get { return (SecureString) GetValue(PasswordProperty); } set { SetValue(PasswordProperty, value); } } public static readonly DependencyProperty PasswordProperty = DependencyProperty.Register("Password", typeof(SecureString), typeof(UserCredentialsInputControl), new PropertyMetadata(default(SecureString))); public PasswordUserControl() { InitializeComponent(); // Update DependencyProperty whenever the password changes PasswordBox.PasswordChanged += (sender, args) => { Password = ((PasswordBox) sender).SecurePassword; }; } }

Ejemplo de uso

El uso del control es muy sencillo, solo vincule la contraseña DependencyProperty en el control a una propiedad de Contraseña en su ViewModel. La propiedad Contraseña de ViewModel debe ser una SecureString.

<controls:PasswordUserControl Password="{Binding Password, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>

Cambie el modo y el activador UpdateSource en el enlace a lo que sea mejor para usted.

Si necesita la contraseña en texto sin formato, la siguiente página describe la forma correcta de convertir entre SecureString y la cadena: http://blogs.msdn.com/b/fpintos/archive/2009/06/12/how-to-properly-convert-securestring-to-string.aspx . Por supuesto que no debes guardar la cadena de texto plano ...


dependiendo de su comprensión de mvvm (en algunos casos, el código está permitido en algunos casos)

Así que creo un PasswordBox y también un TextBlock llamado

Xaml

<PasswordBox Height="23" Width="156" PasswordChar="*" PasswordChanged="pwBoxUser_PasswordChanged"/> <TextBlock Height="1" Width="1" Name="MD5pw" Text="{Binding Passwort, UpdateSourceTrigger=PropertyChanged, Mode=OneWayToSource}" VerticalAlignment="Top" />

código detrás

private void pwBoxUser_PasswordChanged(object sender, RoutedEventArgs e) { var pBox =sender as PasswordBox; string blank=pBox.Password; //to crypt my blank Password var sMD5 = myMD5.toMD5(blank); //implement your crypt logic here blank =""; MD5pw.Text = sMD5; }

Como puede ver, su contraseña está guardada y puede enlazarla fácilmente.