Gigi Labs

Saturday, June 21, 2014

C# WPF/MVVM: Why You Shouldn't Bind PasswordBox Password

Hi! :)

In WPF circles, the PasswordBox control has generated quite a bit of discussion. The thing is that you can access the password entered by the user using the Password property, but it's not a dependency property, and MVVM purists don't like the fact that they can't bind it to their ViewModel.

In this article, I'm going to show how the password can be bound in the ViewModel despite this limitation. And I'm also going to show you why it's a very bad idea to do this. This article is a little advanced in nature, and assumes you're familiar with WPF and MVVM.

Right, so let's set up something we can work with. Create a new WPF application, and then add a new class called MainWindowViewModel. In your MainWindow's codebehind (i.e. MainWindow.xaml.cs), set up your window's DataContext by adding the following line at the end of your constructor:

this.DataContext
= newMainWindowViewModel();

Right, now let's add a couple of properties to our MainWindowViewModel that we'll want to bind to:

publicstring
Username { get;
set;
}

publicstring
Password { get;
set;
}

Now we can build our form by editing the XAML in MainWindow.xaml. Let's go with this (just make sure the namespace matches what you have):

<Window
x:Class="CsWpfMvvmPasswordBox.MainWindow"

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

Title="Login"

Height="120"

Width="325">

<Grid>

<Grid.RowDefinitions>

<RowDefinition
Height="20"
/>

<RowDefinition
Height="20"
/>

<RowDefinition
Height="30"
/>

</Grid.RowDefinitions>

<Grid.ColumnDefinitions>

<ColumnDefinition
Width="90"
/>

<ColumnDefinition
/>

</Grid.ColumnDefinitions>

<TextBlock
Text="Username:"

Grid.Row="0"

Grid.Column="0"

Margin="2"
/>

<TextBox
Text="{Binding
Path=Username}"

Grid.Row="0"

Grid.Column="1"

Margin="2"
/>

<TextBlock
Text="Password:"

Grid.Row="1"

Grid.Column="0"

Margin="2"
/>

<PasswordBox
Password="{Binding
Path=Password}"

Grid.Row="1"

Grid.Column="1"

Margin="2"
/>

<Button
Content="Login"

Grid.Row="2"

Grid.Column="1"

HorizontalAlignment="Right"

Width="100"

Margin="2"
/>

</Grid>

</Window>

Now, you'll notice right away that something's wrong when you see the blue squiggly line at the password binding:

Oh no! What are we going to do now? If we can't bind the password, and have to somehow retrieve it from the control, then we'll break the MVVM pattern, right? And we MVVM knights-in-shining-armour can't afford to deviate from the path of light that is MVVM. You see, the Password property can't be bound specifically because it shouldn't, but let's say that we're like most other developers and we're so blinded by this MVVM dogma that we don't care about the security concerns and we want an MVVM-friendly solution.

Well, no problem! It turns out that there actually is an MVVM-friendly way to bind the password - see the PasswordBoxAssistant and PasswordHelper implementations. To get up and running, let's add a new PasswordBoxHelper class to our project, and add the implementation from the second link:

Now, let's fix our Password binding. First, add the following attribute to the Window declaration in the XAML so that we can access our project's classes (adjust namespace as needed):

xmlns:local="clr-namespace:CsWpfMvvmPasswordBox"

Then update the PasswordBox declaration to use the PasswordBoxHelper as follows:

<PasswordBox
local:PasswordHelper.Attach="True"

local:PasswordHelper.Password="{Binding
Path=Password}"

Grid.Row="1"

Grid.Column="1"

Margin="2"
/>

That did it! The project now compiles.

Now, let's see why what we have done is a very stupid thing to do. To do this, we're going to need this WPF utility called Snoop, so go over to their website, download it, and install it using the .msi file.

Run Snoop. All you'll see is a thin bar with a few buttons. On the right hand side, there is a button that looks like a circle (in fact it's supposed to be crosshairs). If you hover over it, it will explain how to use it:

Run the WPF application we just developed. Enter something into the PasswordBox, but shhhh! Don't tell anyone what you wrote there! :)

Next, drag those crosshairs from Snoop onto the WPF window:

When you let go, a window opens. In the treeview to the left, you can navigate through the mounds of crap that internally make up our simple application. When you find the PasswordBox, you'll also find the PasswordHelper:

...and as you can see, the PasswordHelper keeps the password exposed in memory so anyone who knows what he's doing can gain access to it. With a program like Snoop, anyone can access passwords that are bound.

Secondly, don't be so religious about so-called best practices such as MVVM. Ultimately they are guidelines, and there are many cases such as this where there are more important things to consider (in this case, security). For something as simple as a login window, it's much more practical to just do without MVVM and do everything in the codebehind. It isn't going to affect the scalability, maintainability, robustness [insert architectural buzz-word here], etc of your application if you make an exception that is rational.

Before ending this article, I would like to thank the person who posted this answer to one of my questions on Stack Overflow. That answer helped me understand the dangers of binding passwords, and provided the inspiration for this article. As further reading, you might also want to read this other question (and its answer) which deals with the security of processing passwords in memory in general (not just data binding).