.NET 中機密文本儲存方案

來源:互聯網
上載者:User

Managed 程式碼中的字串是一類特殊的對象,它不可被改變的,每次使用 System.String 類中的方法之一或進行運算時(如賦值、拼接等)時,都要在記憶體中建立一個新的字串對象,也就是為該新對象分配新的空間。這就帶來兩個問題:

1:原來的字串是不是還在記憶體當中?

2:如果在記憶體當中,那麼機密資料(如密碼)該如何儲存才足夠安全?

 

先來看第一個問題:

 

代碼

publicclass Program
{
staticvoid Main(string[] args)
{
Method1(); //在此處打上斷點
Console.ReadKey();
}
staticvoid Method1()
{
string str ="luminji";
Console.WriteLine(str);
}
}

 

 

在Method1處打上斷點,讓VS執行到此處,在即時視窗中運行命令:.load sos.dll 和 !dso,如下:

開啟調試中的記憶體查看視窗,定位到019db820(由!dso得到)。由於此時還沒有進入到Method1,所以記憶體當中不存在字串“luminji”。接著讓程式運行到方法內部,我們看到記憶體當中已經存在了“luminji”了。


接著讓程式繼續運行,退出方法Method1,發現“luminji”依然留在記憶體當中。

這就帶來一個問題,如果有惡意人員掃描你的記憶體,你的程式所儲存的機密資訊將無處可逃。幸好FCL中提供了System.Security.SecureString,SecureString表示一個應保密的文本,在初始化時就已經被加密。

 

代碼

publicclass Program
{
static System.Security.SecureString secureString =new System.Security.SecureString();

staticvoid Main(string[] args)
{
Method2(); //在此處打上斷點
Console.ReadKey();
}
staticvoid Method2()
{
secureString.AppendChar('l');
secureString.AppendChar('u');
secureString.AppendChar('m');
secureString.AppendChar('i');
secureString.AppendChar('n');
secureString.AppendChar('j');
secureString.AppendChar('i');
}
}

 

 

相同的方法,可以發現在進入Method2後,已經找不到對應的字串了。但是,問題隨之而來,核心資料的儲存問題已經解決了,可是文本總是要取出來用的,只要取出來不是就會被發現嗎。沒錯,這個問題沒法避免,但是我們可以做到文本一使用完畢,就釋放掉。

見如下代碼:

 

代碼

staticvoid Method3()
{
secureString.AppendChar('l');
secureString.AppendChar('u');
secureString.AppendChar('m');
secureString.AppendChar('i');
secureString.AppendChar('n');
secureString.AppendChar('j');
secureString.AppendChar('i');
IntPtr addr = Marshal.SecureStringToBSTR(secureString);
string temp = Marshal.PtrToStringBSTR(addr);
//使用該機密文本do something
///=======開始清理記憶體
//清理掉Unmanaged 程式碼中對應的記憶體的值
Marshal.ZeroFreeBSTR(addr);
//清理Managed 程式碼對應的記憶體的值(採用重寫的方法)
int id = GetProcessID();
byte[] writeBytes = Encoding.Unicode.GetBytes("xxxxxx");
IntPtr intPtr = Open(id);
unsafe
{
fixed (char* c = temp)
{
WriteMemory((IntPtr)c, writeBytes, writeBytes.Length);
}
}
///=======清理完畢
}

 

 

注意查看上文代碼:

IntPtr addr = Marshal.SecureStringToBSTR(secureString);
string temp = Marshal.PtrToStringBSTR(addr);

這兩行代碼錶示的就是將機密文本從secureString取出來,臨時賦值給字串temp。這就存在兩個問題,第一行實際調用的是Unmanaged 程式碼,它在記憶體中也會儲存一個“luminji”,第二行代碼是在託管記憶體中儲存一個“luminji”。這兩段文本的釋放方式是不一樣的。前者,可以通過使用:

Marshal.ZeroFreeBSTR(addr);

進行釋放。而託管記憶體中的文本,只能通過重寫來完成(如上文中,就是重寫成為無意義的“xxxxxx”)。

上段代碼涉及到的幾個方法如下:

 

代碼

publicstaticint GetProcessID()
{
Process p = Process.GetCurrentProcess();
return p.Id;
}
publicstatic IntPtr Open(int processId)
{
IntPtr hProcess = IntPtr.Zero;
hProcess = ProcessAPIHelper.OpenProcess(ProcessAccessFlags.All, false, processId);
if (hProcess == IntPtr.Zero)
thrownew Exception("OpenProcess失敗");
processInfo.hProcess = hProcess;
processInfo.dwProcessId = processId;
return hProcess;
}
publicstaticint WriteMemory(IntPtr addressBase, byte[] writeBytes, int writeLength)
{
int reallyWriteLength =0;
if (!ProcessAPIHelper.WriteProcessMemory(processInfo.hProcess, addressBase, writeBytes, writeLength, out reallyWriteLength))
{
//throw new Exception();
}
return reallyWriteLength;
}

[StructLayout(LayoutKind.Sequential)]
internalstruct PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
publicint dwProcessId;
publicint dwThreadId;
}
[Flags]
enum ProcessAccessFlags : uint
{
All =0x001F0FFF,
Terminate =0x00000001,
CreateThread =0x00000002,
VMOperation =0x00000008,
VMRead =0x00000010,
VMWrite =0x00000020,
DupHandle =0x00000040,
SetInformation =0x00000200,
QueryInformation =0x00000400,
Synchronize =0x00100000
}
staticclass ProcessAPIHelper
{
[DllImport("kernel32.dll")]
publicstaticextern IntPtr OpenProcess(ProcessAccessFlags dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, int dwProcessId);
[DllImport("kernel32.dll", SetLastError =true)]
publicstaticexternbool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, int nSize, outint lpNumberOfBytesWritten);
[DllImport("kernel32.dll", SetLastError =true)]
publicstaticexternbool ReadProcessMemory(
IntPtr hProcess,
IntPtr lpBaseAddress,
[Out] byte[] lpBuffer,
int dwSize,
outuint lpNumberOfBytesRead
);
[DllImport("kernel32.dll", SetLastError =true)]
[return: MarshalAs(UnmanagedType.Bool)]
publicstaticexternbool CloseHandle(IntPtr hObject);
}

 

 

 

總結:

1:機密文本使用System.Security.SecureString儲存;

2:System.Security.SecureString被釋放後使用Marshal.ZeroFreeBSTR清除在記憶體中的痕迹;

3:託管字串只能使用重寫記憶體進行清除;

有關利用sos.dll調試Unmanaged 程式碼,查看http://www.cnblogs.com/luminji/archive/2011/01/27/1946217.html

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.