Is Securestring Ever Practical in a C# Application

Is SecureString ever practical in a C# application?

There are actually very practical uses of SecureString.

Do you know how many times I've seen such scenarios? (the answer is: many!):

  • A password appears in a log file accidentally.
  • A password is being shown at somewhere - once a GUI did show a command line of application that was being run, and the command line consisted of password. Oops.
  • Using memory profiler to profile software with your colleague. Colleague sees your password in memory. Sounds unreal? Not at all.
  • I once used RedGate software that could capture the "value" of local variables in case of exceptions, amazingly useful. Though, I can imagine that it will log "string passwords" accidentally.
  • A crash dump that includes string password.

Do you know how to avoid all these problems? SecureString. It generally makes sure you don't make silly mistakes as such. How does it avoid it? By making sure that password is encrypted in unmanaged memory and the real value can be only accessed when you are 90% sure what you're doing.

In the sense, SecureString works pretty easily:

1) Everything is encrypted

2) User calls AppendChar

3) Decrypt everything in UNMANAGED MEMORY and add the character

4) Encrypt everything again in UNMANAGED MEMORY.

What if the user has access to your computer? Would a virus be able to get access to all the SecureStrings? Yes. All you need to do is hook yourself into RtlEncryptMemory when the memory is being decrypted, you will get the location of the unencrypted memory address, and read it out. Voila! In fact, you could make a virus that will constantly scan for usage of SecureString and log all the activities with it. I am not saying it will be an easy task, but it can be done. As you can see, the "powerfulness" of SecureString is completely gone once there's a user/virus in your system.

You have a few points in your post. Sure, if you use some of the UI controls that hold a "string password" internally, using actual SecureString is not that useful. Though, still, it can protect against some stupidity I've listed above.

Also, as others have noted, WPF supports PasswordBox which uses SecureString internally through its SecurePassword property.

The bottom line is; if you have sensitive data(passwords, credit-cards, ..), use SecureString. This is what C# Framework is following. For example, NetworkCredential class stores password as SecureString. If you look at this, you can see over ~80 different usages in .NET framework of SecureString.

There are many cases when you have to convert SecureString to string, because some API expects it.

The usual problem is either:

  1. The API is GENERIC. It does not know that there's a sensitive data.
  2. The API knows that it's dealing with sensitive data and uses "string" - that's just bad design.

You raised good point: what happens when SecureString is converted to string? This can only happen because of the first point. E.g. the API does not know that it's sensitive data. I have personally not seen that happening. Getting string out of SecureString is not that simple.

It's not simple for a simple reason; it was never intended to let the user convert SecureString to string, as you stated: GC will kick in. If you see yourself doing that, you need to step back and ask yourself: Why am I even doing this, or do I really need this, why?

There's one interesting case I saw. Namely, the WinApi function LogonUser takes LPTSTR as a password, which means you need to call SecureStringToGlobalAllocUnicode. That basically gives you unencrypted password that lives in unmanaged memory. You need to get rid of that as soon as you're done:

// Marshal the SecureString to unmanaged memory.
IntPtr rawPassword = Marshal.SecureStringToGlobalAllocUnicode(password);
try
{
//...snip...
}
finally
{
// Zero-out and free the unmanaged string reference.
Marshal.ZeroFreeGlobalAllocUnicode(rawPassword);
}

You can always extend the SecureString class with an extension method, such as ToEncryptedString(__SERVER__PUBLIC_KEY), which gives you a string instance of SecureString that is encrypted using server's public key. Only server can then decrypt it. Problem solved: Garbage Collection will never see the "original" string, as you never expose it in managed memory. This is exactly what is being done in PSRemotingCryptoHelper (EncryptSecureStringCore(SecureString secureString)).

And as something very almost-related: Mono SecureString does not encrypt at all. The implementation has been commented out because ..wait for it.. "It somehow causes nunit test breakage", which brings to my last point:

SecureString is not supported in everywhere. If the platform/architecture does not support SecureString, you'll get an exception. There's a list of platforms that are supported in the documentation.

A SecureString is safe as global application variable?

Centralizing data that is meant to be reused across an application is a standard design pattern. Let's say you have a group of web pages on top of which you wanna display the name of the user, or you need to cache the posts or profile of a particular user. Different frameworks provide different tools for this purpose, for instance in Vue.js, Vuex is offered to implement this mechanism.

In case of your question, you have not specified which framework you are using, whether it is ASP.Net, WPF, or even a pure C# application relying on OWIN. But yet no issues, there are a few ways that can allow you to achieve what you are after and you can chose whichever best suites your needs:

1- You can develop a cache layer in your app, and cache the password or other data through the lifecyle of a particular session. To do this, you can either rely on a "Concurrent Collection" or you can make use an EF Core In-Memory database. (IMemeoryCache is also available in ASP.Net Core)

2- In case the password is meant to undergo some interops, then I recommend you to go for a global cache server. To do so, you can use Redis or Alachisoft NCache.

3- In case that is a web application, then you can preserve the data in a cookie or the local storage of browser.

Keep in mind, the SecureString may not give you any security advantage as you expect with respect to the fact that as stated by Microsoft:

A SecureString object is similar to a String object in that it has a text value. However, the value of a SecureString object is pinned in memory, may use a protection mechanism, such as encryption, provided by the underlying operating system, can be modified until your application marks it as read-only, and can be deleted from computer memory either by your application calling the Dispose method or by the .NET Framework garbage collector.

That said; you have to look at the security aspect of this type from the perspective of memory and memory management. Finally, you have to implement your own security provider, such as hash generation or encryption in other achieve real security.

When would I need a SecureString in .NET?

I would stop using SecureString . Looks like PG guys are dropping support for it. Possibly even pull it in the future - https://github.com/dotnet/apireviews/tree/master/2015-07-14-securestring .

We should remove encryption from SecureString across all platforms in .NET Core - We should obsolete SecureString - We probably shouldn't expose SecureString in .NET Core

Is SecureString a write-only class?

Both ways here, a way to convert it to a securestring and from a securestring. Of course the whole point of storing it in a securestring is to prevent it from being in memory in the first place.

        #region SecureString Manipulation
/// <summary>
/// Convert a Securestring to a regular string (not considered best practice, but make sure it's not in memory if you can help it)
/// </summary>
/// <param name="securePassword">Password stored in a secure string</param>
/// <returns>regular string of securestring password</returns>
public static string ConvertToUnsecureString(this System.Security.SecureString securePassword)
{
if (securePassword == null)
throw new ArgumentNullException("securePassword");

IntPtr unmanagedString = IntPtr.Zero;
try
{
unmanagedString = Marshal.SecureStringToGlobalAllocUnicode(securePassword);
return Marshal.PtrToStringUni(unmanagedString);
}
finally
{
Marshal.ZeroFreeGlobalAllocUnicode(unmanagedString);
}
}

/// <summary>
/// Pass a text password to this function to return a SecureString (doesn't store the password in memory)
/// </summary>
/// <param name="password">Text version of a password</param>
/// <returns>SecureString of a password (not readable by memory)</returns>
public static SecureString ConvertToSecureString(this string password)
{
if (password == null)
throw new ArgumentNullException("password");

var secure = new SecureString();
foreach (var c in password.ToCharArray())
secure.AppendChar(c);
return secure;
}
#endregion

Is it always unsecure if I pass a password as a string and not as a secure string?

If your environment (GUI, storage, data access objects, ...) supports SecureString, then keep the passwords in SecureString as long as you can (all the way if possible). If not, there is no other choice as to use a string.

Using SecureString is an advantage, because the app can control the memory containing the password and can clean it up if not used anymore (a string depends on the garbage collector). On the other side it gives an attacker a clue of where to look for interesting information, though with having access to the memory already this seems not to be a big thing.

To answer your question, no it doesn't make your application unsecure, but if there is the possibility to keep the password in SecureString all the way, it should be done.

Using SecureString

You could use Linq:

"fizzbuzz".ToCharArray().ToList().ForEach(p => secureString.AppendChar(p));

Safe use of SecureString for login form

If you believe that you need SecureString you must believe that an attacker can read your process memory, too. If the latter is true he can read the password characters as they are typed, or read from the textbox internal character buffer directly, or read pixels off the screen.

This is an unrealistic scenario. Don't use SecureString. It helps little and steals your time.

Cold boot attacks are more real, yet extremely uncommon. They require physical machine access which usually totally owns the machine. Reading by the attacker is the least of your concerns in this case.

Basically, you have to contrive a case where your developer time is well spent using SecureString.



Related Topics



Leave a reply



Submit