使用 .NET 2.0 SecureString 类保护敏感数据

什么时候应当使用SecureString类

你可能感到怀疑,既然可以使用基本的String类,为什么还有必要使用SecureString类呢?问题在于String类的设计方面。例如,如果你有一个String类的实例包含某个人的社会安全号,你就希望应用程序在处理过程中将其安全保存,以避免泄露。

 

问题的关键在于安全保存文本,因为String类将其以明文形式保存。查明数据的保存位置需要对.NET字符串有一定了解。.NET字符串是不可变的。也就是说,字符串值的每一个变化都在内存中建立一个新的字符串。因此,内存中的各种敏感数据可能会被不严格的代码或用户访问。

 

这并不是说明为什么使用StringBuilder对象的最有效方法和解释。由于垃圾收集功能,你可能认为这并不是一个太大的问题,但利用.NET垃圾收集使用字符串恢复内存没有确定性。因此,如果数据确实十分敏感,你应当避免String类,而选择SecureString类这些其它方法。

SecureString类具有以下特性:

 

  • 它对保存在内存中的字符串值进行加密。它利用数据保护API(DPAPI),因此它只能在基于NT的平台上使用。
  • SecureString类遵循IDisposable模式。
  • 加密文本不能被轻易解密;也就是说,不存在可以迅速阅读字符串内容的ToString类(没人说过加密很容易)。

一个简单的事例:

System.Security.SecureString ss = new System.Security.SecureString();

ss.AppendChar('T');

ss.AppendChar('e');

ss.AppendChar('c');

ss.AppendChar('h');

ss.AppendChar('R');

ss.AppendChar('e');

ss.AppendChar('p');

ss.AppendChar('u');

ss.AppendChar('b');

ss.AppendChar('l');

ss.AppendChar('i');

ss.AppendChar('c');

ss.AppendChar('.');

ss.AppendChar('c');

ss.AppendChar('o');

ss.AppendChar('m');

Console.WriteLine(ss);

增加最后一个字符后,以上代码用MakeReadOnly方法锁定字符串值。这意味着这个值不能被修改。使数据只读后,一旦你企图修改数据,就会出现异常。你会注意到,在执行时,代码只显示类的名称(System.Security.SecureString)。

 

获得数据

 

像.NET Framework的大多数对象一样,SecureString类也提供一个ToString方法。但是,ToString方法源于基本的System.Object类,在SecureString类中它不能被忽略。因此,调用SecureString类的ToString方法只显示对象(System.Security.SecureString)的类型,而没有实际的值。

 

应用SecureString类的难点在于如何恢复保存在其中的数据。因为它使用Windows的加密服务,要利用它,你需要使用System.Runtime命名空间。下面的C#代码是恢复数据的第一个步骤。它将SecureString类的内容复制到一个长指针对象中。

 

IntPtr pointerName = System.Runtime.InteropServices.Marshal.SecureStringToBSTR(SecureString object);

 

    植入指针对象后,指针通过System.Runtime.InteropServices.Marshal类转换为一个字符串。这一操作由以下C#代码完成:

 

Console.WriteLine(System.Runtime.InteropServices.Marshal.PtrToStringBSTR(bstr));

 

微软文件指出,转换对象到一个指针分配了一个字符串所需的未管理内存,因此任务完成后你应当总是通过调用ZeroFreeBSTR方法释放指针对象,如以下的C#所示:

 

    System.Runtime.InteropServices.Marshal.ZeroFreeBSTR(bstr);

 

下面的C#代码将在SecureString对象中保存数据与恢复数据、保存和显示内容的例子结合起来:

 

System.Security.SecureString ss = new System.Security.SecureString();

ss.AppendChar('T');

ss.AppendChar('e');

ss.AppendChar('c');

ss.AppendChar('h');

ss.AppendChar('R');

ss.AppendChar('e');

ss.AppendChar('p');

ss.AppendChar('u');

ss.AppendChar('b');

ss.AppendChar('l');

ss.AppendChar('i');

ss.AppendChar('c');

ss.AppendChar('.');

ss.AppendChar('c');

ss.AppendChar('o');

ss.AppendChar('m');

Console.WriteLine(ss);

 

IntPtr ptr = System.Runtime.InteropServices.Marshal.SecureStringToBSTR(ss);

try

{

Console.WriteLine(System.Runtime.InteropServices.Marshal.PtrToStringBSTR(ptr));

}

finally

{

System.Runtime.InteropServices.Marshal.ZeroFreeBSTR(ptr);

}

posted on 2007-06-22 10:17  Sherrys  阅读(1646)  评论(0编辑  收藏  举报

导航