2014-02-28 40 views
1

我想從內存中刪除任何正常字符串的痕跡,這樣做我從正常字符串的引用創建SecureString的實例。像這樣:在內存中燃燒System.String

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

的問題是,即使調用Dispose方法後input內容是不改變。從我的理解SecureString實例應該引用input地址,因此如果從Dispose()調用內存清理。我錯過了什麼?

+1

它仍然存在,因爲'input'依然存在。你已經處理了'SecureString',但沒有處理'input'字符串中傳遞的原始數據。我想如果你真的想要處理一個'string',你將不得不用'SecureString'啓動*。 –

+1

另外,如果你這樣做是爲了擺脫密碼的字符串實例,那麼你做錯了。 ;) –

+3

即使你設法做你想做的事情(即使用指針並寫上字符串的內容),也不能保證它只是字符串的副本(即GC可能已經移動了對象10次並留下痕跡遍佈整個內存)。另外不要忘記源代碼中的字符串會被加密,所以要小心清理它們(不太可能是你想要做的事情,但是請記住)。 –

回答

4

看起來the two parameter constructor不適用於您的代碼。該文檔尚不清楚,但它使用短語Initializes a new instance of the SecureString class from a subarray of System.Char objects告訴我它可能正在複製數據,而不是對現有字符串進行加密。這是有道理的,因爲SecureString的文檔具體提到String不能以確定性方式銷燬。

測試這個理論的一個好方法是比較inputsecure的地址,看它們在初始化後是否仍然指向內存中的相同位置。

+1

是的,檢查這兩個變量的內存地址是我嘗試的第一件事情之一,而且他們實際上並不指向同一個地方。 –

+0

'secure'不可能具有與'input'相同的地址,因爲它是一個.Net對象。這意味着它必須包含正常的對象標題。 – svick

0

這不是真的意味着答案,因爲沒有辦法確定字符串還沒有在內存中浮動,但我想我會發布這個,因爲它確實修改了它原來的字符串拜訪。


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); 
     } 
    } 
} 

測試示例代碼,我能想出這個。不保證它不會泄漏內存,但會「燒」調用字符串。雖然你的字符串可能仍然在其他地方的內存中浮動。

+0

哦,這太邪惡了。你可能在共享字符串甚至文字上塗寫。 – usr

+0

@usr我同意=) – TyCobb

2

string對象是共享的。誰知道什麼是代碼引用input字符串?安全決策可以基於它。

因此,字符串在.NET中必須始終是不可變的。你不能殺死它的內容(以文件記錄的方式)。

input甚至可能引用字符串文字!如果您更改其內容,則不相關代碼中的文字可能會更改其值。您在運行時編寫"x"並獲得"\0"。這太可怕了。

此外,GC可以移動物體。你的祕密數據可能已經泄漏到整個堆。以不需要銷燬數據的方式構建應用程序,或者僅將其存儲在固定/非託管緩衝區中。

+0

「你不能殺死它的內容(以書面的方式)。」不會直接修改指針數量?像'fixed(char * p = s){p [0] ='x'; }'。 – svick

+0

@svick是有記錄和支持的嗎?如果我沒有別的選擇,我會這樣做,但只有那樣。 – usr

+0

嗯,你是對的,C#規範明確地說這是一個未定義的行爲:「通過固定指針修改託管類型的對象可能導致未定義的行爲。例如,因爲字符串是不可變的,程序員有責任確保指向固定字符串的指針引用的字符不被修改。「 – svick