位置:海鸟网 > IT > ASP.NET >

C#中机密文本的保存方案

托管代码中的字符串是一类特殊的对象,它不可被改变的,每次使用 System.String 类中的方法之一或进行运算时(如赋值、拼接等)时,都要在内存中创建一个新的字符串对象,也就是为该新对象分配新的空间。这就带来两个问题:

1:原来的字符串是不是还在内存当中?

2:如果在内存当中,那么机密数据(如密码)该如何保存才足够安全?

先来看第一个问题:

代码

publicclass Program
{
static Console.ReadKey();
}
staticvoid Method1()
{

在Method1处打上断点,让VS执行到此处,在即时窗口中运行命令:.load sos.dll 和 !dso,如下:


接着让程序继续运行,退出方法Method1,发现“luminji”依然留在内存当中。

这就带来一个问题,如果有恶意人员扫描你的内存,你的程序所保存的机密信息将无处可逃。幸好FCL中提供了System.Security.SecureString,SecureString表示一个应保密的文本,在初始化时就已经被加密。

代码

publicclass Program
{
new System.Security.SecureString();

static Console.ReadKey();
}
static

相同的方法,可以发现在进入Method2后,已经找不到对应的字符串了。但是,问题随之而来,核心数据的保存问题已经解决了,可是文本总是要取出来用的,只要取出来不是就会被发现吗。没错,这个问题没法避免,但是我们可以做到文本一使用完毕,就释放掉。

见如下代码:

代码

static Marshal.SecureStringToBSTR(secureString);
Marshal.PtrToStringBSTR(addr);
Marshal.ZeroFreeBSTR(addr);
GetProcessID();
Open(id);
unsafe
{
temp)
{
WriteMemory((IntPtr)c, writeBytes, writeBytes.Length);
}
}

注意查看上文代码:

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

这两行代码表示的就是将机密文本从secureString取出来,临时赋值给字符串temp。这就存在两个问题,第一行实际调用的是非托管代码,它在内存中也会存储一个“luminji”,第二行代码是在托管内存中存储一个“luminji”。这两段文本的释放方式是不一样的。前者,可以通过使用:

Marshal.ZeroFreeBSTR(addr);

进行释放。而托管内存中的文本,只能通过重写来完成(如上文中,就是重写成为无意义的“xxxxxx”)。

上段代码涉及到的几个方法如下:

代码

publicstatic Process.GetCurrentProcess();
return p.Id;
}
public, processId);
IntPtr.Zero)
throw processId;
return hProcess;
}
publicstatic writeLength)
{
0;
reallyWriteLength))
{
}
return reallyWriteLength;
}

[StructLayout(LayoutKind.Sequential)]
internalstruct PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
publicint dwProcessId;
publicint dwThreadId;
}
[Flags]
0x00100000
}
static)]
publicstatictrue)]
publicstaticexterntrue)]
publicstaticextern[] lpBuffer,
int dwSize,
out: MarshalAs(UnmanagedType.Bool)]
publicstaticexternbool CloseHandle(IntPtr hObject);
}

总结:

1:机密文本使用System.Security.SecureString保存;

2:System.Security.SecureString被释放后使用Marshal.ZeroFreeBSTR清除在内存中的痕迹;

3:托管字符串只能使用重写内存进行清除;

有关利用sos.dll调试非托管代码,查看