Are your string Passwords safe?

Ok, so the title is quite broad. In this article we will look at how using strings for passwords or sensitive data are not safe. Also we will look at the SecureString class and see if and how it can solve some safety concerns.

TopSecret

So let’s set the stage by creating a Top Secrect WPF application:

  • Only the president can access our system
  • He enters his password and clicks “Login”.
  • The App validates the password and signs him in.
  • The App navigates to the Home page.
  • He leaves and his secretary starts working in the system.

But this password is also used for the Nuclear Launch codes, so once the president has signed in, the application may not reveal the password or allow a user to change the password.

LaunchCodes

Great, here’s some xaml for the login screen, we have a PasswordBox (since this is a Top Secret App) and a login button:


<StackPanel>
   <TextBlock Text="Enter secret password" />
   <PasswordBox x:Name="pbPassword"/>
   <Button Content="Login" Click="Login_Click"/>
</StackPanel>

And the code behind looks like this:


private void Login_Click(object sender, RoutedEventArgs e)
{
   if (verifyPasswordInDatabase(pbPassword.Password))
   {
      NavigationService nav = NavigationService.GetNavigationService(this);
      nav.Navigate(new Uri("HomePage.xaml", UriKind.RelativeOrAbsolute));
   }
}

private bool verifyPasswordInDatabase(string password)
{
   // Send password to db and verify...
   return true;
}

All that happens here is we get the password from pbPassword.Password, verify it (just return true for demo sake) and then navigate to the HomePage.xaml.

Once we’re in the application, we’re done with the password, it’s out of scope and no need to worry about anyone getting hold of it right?

Wrong! We’re on the home page, out of scope of the login page and looking at the Memory Heap (I used the Memory Window in Visual Studio). In clear text we can see the password in memory, J@mesBond007.

MemoryHeap

Why is the password still in memory, even though it was just used in a variable within a method which is completely out of scope by now? Well, that’s simply because the Garbage Collector (GC) hasn’t made its round to clean this up.

Stressing about password in memory, Seriously?

So is it really worth worrying about what values are left behind in memory? Only hardcore hackers would go so far as to steal the president’s password from memory!? Let’s see…

If we have a client – server based setup (e.g. Asp.Net or a server hosted Web Service) and our string value is on the server, then this probably isn’t a real concern, Phew!

But what about our Top Secret WPF App, it’s a client application? We were able to find the password in the Memory Heap earlier, but that’s because we can easily debug and find the memory address of the password variable with the help of Visual Studio. How hard would it be to write an app to do so?

Unfortunately it’s a lot easier than suspected. Reading the memory of a process is not isolated to the domain of hackers and experts, but with the help of this article, even I, with barely any knowledge on the topic was able to write a small app to dump the memory of our Top Secret App to a text file. Here’s the password in our memory dump file:

MemoryDumpFile

There we have it! If I was able to get the password of another application with my basic understanding of the topic, then it’s a breeze for anyone with a bit of savvy. The memory dump text file of our app is about 9 MB. So there’s a lot of text to sift through in order to find the password. The easiest way to sift is to look for queues that might be near the password in memory. In this case, the HomePage was a great queue. Since the Top Secret App navigates to the HomePage once logged in, it’s a good place to start looking for references to “Home” or “Index” or “Default”.

Another reason why it’s imperative not to hold our password in memory, is that if our system crashes and a memory dump is captured it will leave the value J@mesBond007 in clear text in the dump file.

What’s our solution?

Some poor attempts at a solution…

Let’s spitball some ideas to prevent our password hanging around in memory.

# What if we set the password variable to null right after using it. That should replace the J@mesBond007 value in memory.

Wrong! string is immutable, so “changing” a string value simply makes a new copy in memory.

# Let’s make sure we have no references to our password string and limit it’s scope of use. Hopefully the GC will reclaim the space in memory.

Nope… The GC doesn’t run when objects are out of scope

# Ok then, when we’re done using the password, we’ll force the GC to reclaim the space in memory using GC.Collect();

This will tell the GC it needs to collect, but does not guarantee that the GC will collect immediately.

# Well, let’s force a wait until the GC has completed, GC.WaitForPendingFinalizers();

Forcing a manual Garbage collection is usually not a good idea, especially waiting for all finalizers to complete. Not only that, but we STILL cannot guarantee that the password will be collected, even more so if the string has been interned.

String intering – since a string is immutable, the CLR can place a string into an intern pool. If mulitple strings have the same value, they can all point to the single value in the intern pool instead of each having their own copy of their value. This is to save space in memory.

Heading in a better direction?

There is a player which we haven’t mentioned yet, SecureString (a .NET class from the System.Security namespace).

  • The value of a SecureString is stored encrypted into memory. This means no more clear text values in memory
  • Another benefit is that it implements IDisposable, giving us some control over the password’s lifetime in memory.
  • There are no constructors or methods which take a string parameter, preventing any string instance of our password to be found in memory.
  • The WPF’s password box has a property SecurePassword which provides us with a SecureString instance of the user-typed password instead of a string instance.

Let’s use our password in the SecureString instance.

# Let’s find the method on the class which returns the password value

There is no such method. A method like this would compromise the security and leave the password in plain text in memory.

# Of course, silly me. So let’s try pass the SecureString to our SQL Database and validate the password there.

There is no SQL data type for our SecureString to be passed as a parameter.

What do we do now? We have our password, but we can’t use it. There are no “managed” ways to read our password from the SecureString instance. This was intended this way to prevent “un-secure” usage by leaving copies our our value behind in memory. But we can still deal with the values in the unmanaged heap. Sounds pretty scary, but fortunately the System.Runtime.InteropServices.Marshal class helps us out here.

This doesn’t provide us with any solution though. To answer this question, let’s quickly have a look at how our application’s authentication works.

  • Our passwords in the database are hashed (one way encryption).
  • The president enters his password
  • The password needs to be hashed
  • And sent to the database, verify that he is indeed the president.

This is a secure approach since our passwords aren’t vulnerable in the database (hashed) and also if the call to the database is compromised via a sort of profiler, only the hashed password will be exposed, which is useless when trying to log in.

So bearing in mind the above mentioned, we need to get to a hashed value of the password from the SecureString instance, without exposing our value in memory.

# Since we can’t cast to string, what about using the Marshal class to read our value into a byte[] and then apply the hashing algorithm to the byte[]

Unfortunately byte is an immutable value type, so we sit with the same issues as converting it to string. We can still see our password in plain text in memory and cannot explicitly control its lifetime.

# What if we use read the unmanaged bytes, but instead of copying to a managed byte[], we directly apply the hash and bring the “hashed” result back into the managed world?

Now we’re on the right track. We could create a pointer (IntPtr) to read each unmanaged byte of our secure password and hash it as we read it. Our password will readable in memory only as long as the IntPtr instance is alive (in our case, only for a moment) and we’re able to quickly cleanup after ourselves, leaving no password trace in memory.


private static string HashSecureString(SecureString password)
{
   IntPtr unmanagedBytes = Marshal.SecureStringToGlobalAllocAnsi(password);
   try
   {
      byte[] hashedBytes = new byte[password.Length];
      unsafe
      {
         byte* byteArray = (byte*)unmanagedBytes.ToPointer();

         for (int i = 0; i &lt; hashedBytes.Length; ++i)
         {
            // Hash using OR operator
            hashedBytes[i] = (byte)(byteArray[i] | 170);
         }
      }
      return Convert.ToBase64String(hashedBytes);
   }
   finally
   {
      Marshal.ZeroFreeGlobalAllocAnsi(unmanagedBytes);
   }
 }

In the above code, what we’ve done:

  • We’ve read from the unmanaged byte array
  • Then run a hash on each unamanaged byte
  • Stored the hashed byte into a new managed byte array
  • Converted our hashed byte array into a string and returned the value
  • In the finally we are able to clear out our password from memory. Since we’ve used IntPtr to get hold of unmanaged memory, we don’t have to rely on the GC to clear our password from memory.

We now have a hashed string value in memory (back into the managed world, phew) which we can send off to our database to verify the user. After updating our TopSecretApp and writing the memory to file, we see that there are no traces of the president’s password left behind in memory, only our hashed password value.

MemoryDump_Secured

As for the hashing algorithm used, I’ve simply used my own “custom” hash, applying a Bitwise OR operator to each byte and the number 170. I’ve chosen 170 because the binary representation is 10101010 (alternating between 1’s and 0’s), but it will work with other numbers as well (except for 0). The Bitwise OR operator works nicely as a hash since it’s irreversible.

See below an example showing why OR is irreversible. I’ve used 2 different numbers (165  and 7). The result is exactly the same for both. So given the hashed value, you would not know if the original was 165, 7 or any other number which would  produce the same result.


// 165         // 7

10100101       00000111
10101010       10101010
--------       ----------
10101111       10101111

Please don’t use my little hashing technique in production code, use a reputable Hashing algorithm such as MD5 or SHA1. I’ve only used a basic custom hash for demo purposes.

If SecureString is so difficult to use, what’s the point?

This is a very good question. SecureString had given me hope for an easier, secure solution part of the .Net framework. It however took much research and some panel-beating to finally get the desired result. And the fact that my solution reads and hashes bytes from “unmanaged memory” doesn’t exactly make it feel very elegant.

There are however good reasons to use SecureString:

  • To prevent memory dumps exposing sensitive data (as mentioned previously). If we captured a user’s Credit card number, we’d want to make sure that this number never accidentally gets written to a memory dump.
  • If we need to work with SSL certificates, X509Certificate class takes a SecureString as a parameter.
  • Using the SqlConnection.ChangePassword method to change our Sql server password, takes a SecureString password.
  • It may be a good idea to consider using SecureString for building an API which receives a password or sensitive data.

As more and more API’s start using SecureString, it will start to make more sense to use it. In the end, if we create applications which belong to a chain of API’s, it’s best to make sure that at least our API is not the weak link. Finally when the SecureString has been passed around and reached its final destination (hopefully in a secure environment), the password value can be converted back to text (or hashed as in our TopSecretApp).

Fortunately, there are MANY different ways to secure an appliation. Before jumping into any decisions, do some research and find the safest and most maintainable solution for your situation.

A little Gotcha!

When pasting the password into the password box, the password value unfortunately ends up in memory. This is most likely as the Paste Command used probably grabs the value from the clipboard and at some stage keeps it in a string variable. So then we have a clear text password in managed memory which we cannot scrub. A simple work around is to explicitly handle the Paste Command and disallow copy, paste for PasswordBoxes.

Download Source

I’ve uploaded the source for the Top Secret App as well as the console app created to read another process’ memory to GitHub, here are the links:

Advertisements

2 thoughts on “Are your string Passwords safe?

  1. Hi Niels,

    As always … excellent article on something that is not even considered in most applications. One question through, I’ve noticed that you demo application was writeen in WPF, what about WinRT? Would the same scenario apply? I’m guessing the answer is yes.

    Thanks again!

    Like

  2. Hi Richard,

    It seems that SecureString doesn’t exist for WinRT. Base on what I read here, Windows Store Apps are Sandboxed and it’s more difficult for a different process to gain access to the Store App memory. Likely due to this it wasn’t implemented for WinRT.

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s