1

I am trying to remove any traces of a normal string from memory, to do so I am creating an instance of SecureString from a reference of the normal string. Like so:

public static unsafe void Burn(this string input)
{
    fixed (char* c = input)
    {
        var secure = new SecureString(c, input.Length);
        secure.Dispose();
    }
}

The problem is that even after calling the dispose method the contents of input are non-changed. From my understanding the SecureString instance should reference the input address and therefore clean if from memory upon Dispose() call. What am I missing?

John Saunders
  • 160,644
  • 26
  • 247
  • 397
Bruno Klein
  • 3,217
  • 5
  • 29
  • 39
  • 1
    It still exists because `input` still exists. You have disposed of the `SecureString` but not the original passed in `input` string. I think if you really want to dispose of a `string` you would have to *start* with a `SecureString`. – Evan L Feb 28 '14 at 23:34
  • 1
    Also, if you are doing this to get rid of a `string` instance of a password, you are doing it wrong. ;) – Evan L Feb 28 '14 at 23:39
  • 3
    Even if you manage to do what you want (i.e. using pointers and write over content of the string) there is no guarantees that it is only copy of the string (i.e. GC could have moved the object 10 times and left it traces all over the memory). Also don't forget that strings from source are interned so be careful cleaning those up (unlikely what you want to do, but still keep in mind). – Alexei Levenkov Feb 28 '14 at 23:50

3 Answers3

4

It appears the two parameter constructor is not meant to be used by your code. The documentation isn't clear but its use of the phrase Initializes a new instance of the SecureString class from a subarray of System.Char objects tells me it's probably copying the data, not encrypting the existing string in place. This would make sense since the documentation for SecureString specifically mentions a String cannot be destroyed in a deterministic way.

A good way to test this theory would be to compare the addresses of input and secure to see if they still point to the same location in memory after the initialization.

Erik Noren
  • 4,279
  • 1
  • 23
  • 29
  • 1
    Yeah, checking the memory address of both variables was one of the first things I tried, and they in fact don't point to the same place. – Bruno Klein Feb 28 '14 at 23:53
  • `secure` can't possibly have the same address as `input`, since it's a .Net object. That means it has to contain the normal object headers. – svick Mar 02 '14 at 22:52
2

string objects are shared. Who knows what is code is referencing that input string? Security decisions could be based on it.

Therefore, strings must always be immutable in .NET. You cannot kill its contents (in a documented way).

input might even refer to a string literal! If you change its contents, literals in unrelated code might change their value. You write "x" and get "\0" at runtime. This is so horrible.

Furthermore, the GC can move objects around. Your secret data has probably leaked all over the heap already. Construct your app in such a way that it does not require destroying data, or only store it in pinned/unmanaged buffers.

usr
  • 168,620
  • 35
  • 240
  • 369
  • “You cannot kill its contents (in a documented way).” Wouldn't directly modifying the pointer count? Something like `fixed (char* p = s) { p[0] = 'x'; }`. – svick Mar 02 '14 at 22:55
  • @svick is that documented and supported? I'd do that if I had no other choice, but only then. – usr Mar 03 '14 at 10:21
  • Hmm, you are right, the C# spec explicitly says that this is an undefined behavior: “Modifying objects of managed type through fixed pointers can results in undefined behavior. For example, because strings are immutable, it is the programmer's responsibility to ensure that the characters referenced by a pointer to a fixed string are not modified.” – svick Mar 03 '14 at 13:51
0

This isn't really meant as an answer as there is no way to determine that the string isn't still floating in memory somewhere, but I thought I would post this because it does modify the original string that it was called on.


public static class StringTest
{
    public static unsafe void Burn(this string input)
    {
        fixed (char* c = input)
        {
            Marshal.Copy(new string('\0', input.Length).ToCharArray(), 0, new IntPtr(c), input.Length);
        }
    }
}

Testing your sample code, I was able to come up with this. No guarantees that it doesn't leak memory, but it does "burn" the calling string. Your string may still be floating in memory somewhere else though.

TyCobb
  • 8,909
  • 1
  • 33
  • 53
  • Oh this is so evil. You might be scribbling over shared strings or even literals. – usr Mar 01 '14 at 00:20