最近正在编写一个高加密的通讯库,目前写到涉及到密钥销毁,于是就思考如何真正且安全的将密钥“销毁”。
其实论安全来说,最核心的就是:非程序活动时间内,不应该在内存保留密钥数据。于是就衍生出了直接将 array 设置为 null 和 Array.Clear() 两个方法。
接下来就做一个小实验,需要请到大名鼎鼎的作弊工具:Cheat Engine。当然我只需要用到他的内存读取功能。
现在我写了一个这样的代码,定义一个字符串,然后将其转换为数组数据,接着把第一个字符恢复正常以方便在 CE 搜索。
using System.Text;
namespace TestGround
{
internal class Program
{
static void Main(string[] args)
{
string input = "Fxample Mem.";
byte[] toArray = Encoding.ASCII.GetBytes(input);
toArray[0] = (byte)'E';
retry:
Console.WriteLine("1. Null it.");
Console.WriteLine("2. Clear it.");
string read = Console.ReadLine();
switch (read[0]) {
case '1':
Console.WriteLine("Tell GC don't collect.");
if (GC.TryStartNoGCRegion(16384)) {
Console.WriteLine("GC won't collect now.");
}
toArray = null;
Console.WriteLine("Array is null now.");
break;
case '2':
Console.WriteLine("Clear array.");
Array.Clear(toArray, 0, toArray.Length);
Console.WriteLine("Array is cleared now.");
break;
default:
goto retry;
}
Console.ReadLine();
}
}
}
当程序启动后,他只会打印出操作方法,然后经过还原出 "Example Mem." 字符串,我们尝试在 CE 搜索这个字符串,就得出这个结果:
当我们输入 1、回车 的时候,可以发现执行后,内存的字符串依旧在这里。(GC 的自动回收已经在代码里压制了,所以实验结果不受影响)
然后我们就测试一下 Array.Clear() 方法的能力。因为在 C# 里的 Array 引用已经为 null,所以需要重开程序才可以验证,也就是重复上面的步骤。
接着我们输入 2、回车,看看内存发生了什么变化:
可以看到,内存数据已经被抹掉了。
总结:对于一些很敏感的数据,一定要使用 Array.Clear() 方法进行彻底抹除,否则黑客有可能会通过 Dump 内存获取相关信息,从而截获客户的会话、甚至是账号访问权。
用 Cookie 保存: 别名、Email