When would I need a SecureString in .NET?
Asked Answered
C

11

187

I'm trying to grok the purpose of .NET's SecureString. From MSDN:

An instance of the System.String class is both immutable and, when no longer needed, cannot be programmatically scheduled for garbage collection; that is, the instance is read-only after it is created and it is not possible to predict when the instance will be deleted from computer memory. Consequently, if a String object contains sensitive information such as a password, credit card number, or personal data, there is a risk the information could be revealed after it is used because your application cannot delete the data from computer memory.

A SecureString object is similar to a String object in that it has a text value. However, the value of a SecureString object is automatically encrypted, can be modified until your application marks it as read-only, and can be deleted from computer memory by either your application or the .NET Framework garbage collector.

The value of an instance of SecureString is automatically encrypted when the instance is initialized or when the value is modified. Your application can render the instance immutable and prevent further modification by invoking the MakeReadOnly method.

Is the automatic encryption the big payoff?

And why can't I just say:

SecureString password = new SecureString("password");

instead of

SecureString pass = new SecureString();
foreach (char c in "password".ToCharArray())
    pass.AppendChar(c);

What aspect of SecureString am I missing?

Chil answered 26/9, 2008 at 18:43 Comment(1)
11 years later and MS no longer recommends SecureString for new development: github.com/dotnet/platform-compat/blob/master/docs/DE0001.mdHabitation
L
4

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

Ludlow answered 21/7, 2016 at 0:12 Comment(2)
Link is dead but it appears to carry on: learn.microsoft.com/en-us/dotnet/api/… .. with some very weak guidance on path forward execpt "dont use credentials" - github.com/dotnet/platform-compat/blob/master/docs/DE0001.md .. dont you dare use a password to protect the private key of your certificates either!Wilen
After 11 years, this answer looks now to be the 'new' correct one. The links seem to be going stale but guidance from MS is: SecureString shouldn't be usedChil
L
108

Some parts of the framework that currently use SecureString:

The main purpose is to reduce the attack surface, rather than eliminate it. SecureStrings are "pinned" in RAM so the Garbage Collector won't move it around or make copies of it. It also makes sure the plain text won't get written to the Swap file or in core dumps. The encryption is more like obfuscation and won't stop a determined hacker, though, who would be able to find the symmetric key used to encrypt and decrypt it.

As others have said, the reason you have to create a SecureString character-by-character is because of the first obvious flaw of doing otherwise: you presumably have the secret value as a plain string already, so what's the point?

SecureStrings are the first step in solving a Chicken-and-Egg problem, so even though most current scenarios require converting them back into regular strings to make any use of them at all, their existence in the framework now means better support for them in the future - at least to a point where your program doesn't have to be the weak link.

Ledaledah answered 26/9, 2008 at 19:20 Comment(5)
I ran across it looking at ProcessStartInfo's Password property; not even paying attention to the type, I just set it to a regular string until the compiler barked at me.Chil
It wont be easy to find the symmetric encryption key, since SecureString is based on DPAPI, which doesnt exactly store a key in plaintext...Suppose
Also, it's not so much the chicken-and-egg problem, since it's not a replacement for encryption in storage - but its a workaround for immutable, managed .NET strings.Suppose
"you presumably have the secret value as a plain string already, so what's the point?" Is there an answer to this question? It seems like at best it's a "better than nothing" solution if you intend to keep a password stored in memory for a prolonged period.Generable
What about having few simple code examples of usage? I believe I would better understand how and when to use it.Jaf
C
40

Edit: Don't use SecureString

Current guidance now says the class should not be used. The details can be found at this link: https://github.com/dotnet/platform-compat/blob/master/docs/DE0001.md

From the article:

DE0001: SecureString shouldn't be used

Motivation

  • The purpose of SecureString is to avoid having secrets stored in the process memory as plain text.
  • However, even on Windows, SecureString doesn't exist as an OS concept.
    • It just makes the window getting the plain text shorter; it doesn't fully prevent it as .NET still has to convert the string to a plain text representation.
    • The benefit is that the plain text representation doesn't hang around as an instance of System.String -- the lifetime of the native buffer is shorter.
  • The contents of the array is unencrypted except on .NET Framework.
    • In .NET Framework, the contents of the internal char array is encrypted. .NET doesn't support encryption in all environments, either due to missing APIs or key management issues.

Recommendation

Don't use SecureString for new code. When porting code to .NET Core, consider that the contents of the array are not encrypted in memory.

The general approach of dealing with credentials is to avoid them and instead rely on other means to authenticate, such as certificates or Windows authentication.

End Edit : Original Summary below

Lots of great answers; here’s a quick synopsis of what has been discussed.

Microsoft has implemented the SecureString class in an effort to provide better security with sensitive information (like credit cards, passwords, etc.). It automatically provides:

  • encryption (in case of memory dumps or page caching)
  • pinning in memory
  • ability to mark as read-only (to prevent any further modifications)
  • safe construction by NOT allowing a constant string to be passed in

Currently, SecureString is limited in use but expect better adoption in the future.

Based on this information, the constructor of the SecureString should not just take a string and slice it up to char array as having the string spelled out defeats the purpose of SecureString.

Additional info:

  • A post from the .NET Security blog talking about much the same as covered here.
  • And another one revisiting it and mentioning a tool that CAN dump the contents of the SecureString.

Edit: I found it tough to pick the best answer as there's good information in many; too bad there is no assisted answer options.

Chil answered 27/9, 2008 at 11:48 Comment(0)
P
21

Short Answer

why can't I just say:

SecureString password = new SecureString("password");

Because now you have password in memory; with no way to wipe it - which is exactly the point of SecureString.

Long Answer

The reason SecureString exists is because you cannot use ZeroMemory to wipe sensitive data when you're done with it. It exists to solve an issue that exists because of the CLR.

In a regular native application you would call SecureZeroMemory:

Fills a block of memory with zeros.

Note: SecureZeroMemory is is identical to ZeroMemory, except the compiler won't optimize it away.

The problem is that you can't call ZeroMemory or SecureZeroMemory inside .NET. And in .NET strings are immutable; you can't even overwrite the contents of the string like you can do in other languages:

//Wipe out the password
for (int i=0; i<password.Length; i++)
   password[i] = \0;

So what can you do? How do we provide the ability in .NET to wipe a password, or credit card number from memory when we're done with it?

The only way it can be done would be to place the string in some native memory block, where you can then call ZeroMemory. A native memory object such as:

  • a BSTR
  • an HGLOBAL
  • CoTaskMem unmanaged memory

SecureString gives the lost ability back

In .NET, Strings cannot be wiped when you are done with them:

  • they are immutable; you cannot overwrite their contents
  • you cannot Dispose of them
  • their cleanup is at the mercy of the garbage collector

SecureString exists as a way to pass around strings safety, and be able to guarantee their cleanup when you need to.

You asked the question:

why can't I just say:

SecureString password = new SecureString("password");

Because now you have password in memory; with no way to wipe it. It's stuck there until the CLR happens to decide to re-use that memory. You've put us right back where we started; a running application with a password we can't get rid of, and where a memory dump (or Process Monitor) can see the password.

SecureString uses the Data Protection API to store the string encrypted in memory; that way the string will not exist in swapfiles, crash dumps, or even in the local variables window with a colleague looking over your should.

How do i read the password?

Then is the question: how do i interact with the string? You absolutely don't want a method like:

String connectionString = secureConnectionString.ToString()

because now you're right back where you started - a password you cannot get rid of. You want to force developers to handle the sensitive string correctly - so that it can be wiped from memory.

That is why .NET provides three handy helper functions to marshall a SecureString into a unmanaged memory:

You convert the string into an unmanaged memory blob, handle it, and then wipe it again.

Some APIs accept SecureStrings. For example in ADO.net 4.5 the SqlConnection.Credential takes a set SqlCredential:

SqlCredential cred = new SqlCredential(userid, password); //password is SecureString
SqlConnection conn = new SqlConnection(connectionString);
conn.Credential = cred;
conn.Open();

You can also change the password within a Connection String:

SqlConnection.ChangePassword(connectionString, cred, newPassword);

And there are a lot of places inside .NET where they continue to accept a plain String for compatibility purposes, then quickly turn around an put it into a SecureString.

How to put text into the SecureString?

This still leaves the problem:

How do i get a password into the SecureString in the first place?

This is the challenge, but the point is to get you thinking about security.

Sometimes the functionality is already provided for you. For example, the WPF PasswordBox control can return you the entered password as a SecureString directly:

PasswordBox.SecurePassword Property

Gets the password currently held by the PasswordBox as a SecureString.

This is helpful because everywhere you used to pass around a raw string, you now have the type system complaining that SecureString is incompatible with String. You want to go as long as possible before having to convert your SecureString back into regular string.

Converting a SecureString is easy enough:

  • SecureStringToBSTR
  • PtrToStringBSTR

as in:

private static string CreateString(SecureString secureString)
{
    IntPtr intPtr = IntPtr.Zero;
    if (secureString == null || secureString.Length == 0)
    {
        return string.Empty;
    }
    string result;
    try
    {
        intPtr = Marshal.SecureStringToBSTR(secureString);
        result = Marshal.PtrToStringBSTR(intPtr);
    }
    finally
    {
        if (intPtr != IntPtr.Zero)
        {
            Marshal.ZeroFreeBSTR(intPtr);
        }
    }
    return result;
}

They just really don't want you doing it.

But how do i get a string into a SecureString? Well what you need to do is stop having a password in a String in the first place. You needed to have it in something else. Even a Char[] array would be helpful.

That's when you can append each character and wipe the plaintext when you're done:

for (int i=0; i < PasswordArray.Length; i++)
{
   password.AppendChar(PasswordArray[i]);
   PasswordArray[i] = (Char)0;
}

You need your password stored in some memory that you can wipe. Load it into the SecureString from there.


tl;dr: SecureString exists to provide the equivalent of ZeroMemory.

Some people don't see the point in wiping the user's password from memory when a device is locked, or wiping wiping keystrokes from memory after they'authenticated. Those people do not use SecureString.

Pease answered 16/12, 2016 at 21:17 Comment(0)
H
15

There are very few scenarios where you can sensibly use SecureString in the current version of the Framework. It's really only useful for interacting with unmanaged APIs - you can marshal it using Marshal.SecureStringToGlobalAllocUnicode.

As soon as you convert it to/from a System.String, you've defeated its purpose.

The MSDN sample generates the SecureString a character at a time from console input and passes the secure string to an unmanaged API. It's rather convoluted and unrealistic.

You might expect future versions of .NET to have more support for SecureString that will make it more useful, e.g.:

  • SecureString Console.ReadLineSecure() or similar to read console input into a SecureString without all the convoluted code in the sample.

  • WinForms TextBox replacement that stores its TextBox.Text property as a secure string so that passwords can be entered securely.

  • Extensions to security-related APIs to allow passwords to be passed as SecureString.

Without the above, SecureString will be of limited value.

Harday answered 26/9, 2008 at 19:2 Comment(0)
F
12

I believe the reason why you have to do character appending instead of one flat instantiation is because in the background passing "password" to the constructor of SecureString puts that "password" string in memory defeating the purpose of secure string.

By appending you are only putting a character at a time into memory which is likley not to be adjacent to each other physically making it much harder to reconstruct the original string. I could be wrong here but that's how it was explained to me.

The purpose of the class is to prevent secure data from being exposed via a memory dump or similar tool.

Falco answered 26/9, 2008 at 18:47 Comment(0)
P
11

MS found that on certain instances of causing the server (desktop, whatever) to crash there were times when the runtime environment would do a memory dump exposing the contents of what's in memory. Secure String encrypts it in memory to prevent the attacker from being able to retrieve the contents of the string.

Psychotomimetic answered 26/9, 2008 at 18:49 Comment(0)
H
5

One of the big benefits of a SecureString is that it is supposed avoid the possibility of your data being stored to disk due to page caching. If you have a password in memory and then load a large program or data set, your password may get written to the swap file as your program is paged out of memory. With a SecureString, at least the data will not be sitting around indefinitely on your disk in clear text.

Horatio answered 26/9, 2008 at 18:55 Comment(0)
H
4

I guess it's because the string is meant to be secure, i.e. a hacker should not be able to read it. If you initialize it with a string, the hacker could read the original string.

Helwig answered 26/9, 2008 at 18:46 Comment(0)
A
4

Well, as the description states, the value is stored encrypted, with means that a memory dump of your process won't reveal the string's value (without some fairly serious work).

The reason you can't just construct a SecureString from a constant string is because then you would have an unencrypted version of the string in memory. Limiting you to creating the string in pieces reduces the risk of having the whole string in memory at once.

Atonal answered 26/9, 2008 at 18:51 Comment(2)
If they are limiting the construction from a constant string, then the line foreach (char c in "password".ToCharArray()) would defeat that, no? It should be pass.AppendChar('p'); pass.AppendChar('a');etc?Chil
Yes, you can easily enough throw away what little protection SecureString gives you. They're trying to make it hard to completely shoot yourself in the foot. Obviously there has to be some way to get the value into and out of a SecureString, or you couldn't use it for anything.Atonal
L
4

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

Ludlow answered 21/7, 2016 at 0:12 Comment(2)
Link is dead but it appears to carry on: learn.microsoft.com/en-us/dotnet/api/… .. with some very weak guidance on path forward execpt "dont use credentials" - github.com/dotnet/platform-compat/blob/master/docs/DE0001.md .. dont you dare use a password to protect the private key of your certificates either!Wilen
After 11 years, this answer looks now to be the 'new' correct one. The links seem to be going stale but guidance from MS is: SecureString shouldn't be usedChil
K
1

Another use case is when you are working with payment applications (POS) and you simply can't use immutable data structures in order to store sensitive data because you are careful developer. For instance: if I will store sensitive card data or authorisation metadata into immutable string there always would be the case when this data will be available in memory for significant amount of time after it was discarded. I cannot simply overwrite it. Another huge advantage where such sensitive data being kept in memory encrypted.

Kus answered 31/10, 2017 at 3:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.