SecureString in .Net V2

I have been playing with the SecureString class in .Net V2 lately (System.Security.SecureString). Its one of those incremental changes to the framework that is nice to have.

Briefly, the SecureString holds a strings contents in memory in encrypted form (using DPAPI). A standard string is held in memory and is often used to contain sensitive data like connection strings, credit card details, whatever. The standard string is immutable meaning once allocated, you can't overwrite it so there is no easy way to clear it. The garbage collector can move this around (i.e. its not pinned), potentially keeping many copies of the string in memory at any one time. These memory contents can make their way into SWAP files, where its a lot easier to be found.

So, the SecureString is 'pinned' so the GC cannot move it around, its contents are encrypted using DPAPI, so whether its in memory or the SWAP file, you cannot examine its contents easily. It is mutable, so it can also be 'cleared' or zero'ed out effectively erasing its contents from memory, not simply marking it for collection.

Sounds ok, and you'd only use it in certain situations, but I was curious as to what the cost is.

Ease of use is an obvious cost (although I am more concerned with performance right now). The SecureString requires you to add characters into it, rather than assigning a string, for obvious reasons. Once you construct a string object, its in memory, and the advantage of secure string is useless as its already in memory in plain text. So the code might be:

SecureString secret = new SecureString();
secret.AppendChar('H');
secret.AppendChar('i');

Also retrieving that string later involves some interop marshalling. The code below shows an example:

IntPtr ptr = Marshal.SecureStringToBSTR(secret);
string myRegularString = Marshal.PtrToStringUni(ptr));

So the code is a little more, nothing too hairy though. I wondered about the performance cost of this though. Not that performance is going to be a real issue as I would not envision its use for a large number of string operations, but I was curious anyway. I wrote some code to add a standard string obejct to a StringBuilder 10000 times, and to add the contents of a SecureString (containing the same text as the standard string) to a StringBuilder the same amount of times (10000). The results are below:

As you would expect, a pretty reasonable hit, given the encryption and marshalling that needs to occur.

 

4 Comments

  • Even now when we have SecureString it is not so useful when you write in c# or another language which does not allow building your own "unmanaged" strings... In c# SecureString is almost useless... I hope the next beta version of .net ot the final version respectively will offer us a solution.

  • For a secure string to continue to be secure, you MUST guard any String equivalents of it very closely.



    In your example, you converted a secure string into a regular .NET String. BANG, now that "SecureString" is no longer secure: the GC will now "manage" the string instance, and it willl remain in process memory until the next GC, which might not happen for several minutes, or possibly hours.



    You should instead example PROPER secure string code by instead marshalling to a BSTR, wrapped in a try/finally to ENSURE the unencrypted string contents are ZEROED out.



    Theres also a way to CLEAR the managed immutable strings (using c# unsafe code) to ZERO out the characters in the managed string, further enhancing security of the SecureString contents.







  • Eric,



    You are absolutely right about when the string is retrieved into a regular string. Once there, its effectively an "insecure" string. I just wanted to show a simple example to extract it, and more so to measure the cost of it. You are right though, and I will amend the code to suit a more typical secure usage.

  • I don't think it's usable since you need to use unmanaged memory to access it. It sounds against the vista rules for app certification process. What do you think?

Comments have been disabled for this content.