上回写了关于SecureString的特征和为什么我们要使用它,这篇继续研究研究这个SecureString。

**主要内容:**

- SecureString与String之间的转换
- SecureString的基本操作
- 如何销毁一个String? ##SecureString与String之间的转换
###SecureString --> String的转换 我们可以使用[Marshal类](http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.marshal(v=vs.110).aspx)提供的一些方法进行这个转换。 Marshal类并不支持直接将`SecureString`转成托管的`System.String`对像,它提供的方法只能将`SecureString`转成一些非托管的字符串类型。我们需要再做一次转换才能得到`System.String`对象。所以基本的转换思路是这样的: *SecureString --> BSTR/Unicode/ANSI --> System.String* 下面是代码,特别需要注意的地方是,我们一定要把非托管的字符串正确的释放掉。所以`Marshal.ZeroFreeBSTR`放在`Finally`块里确保一定会被执行。 ```
IntPtr bstr = IntPtr.Zero;
try
{
bstr = Marshal.SecureStringToBSTR(sstr);
var str = Marshal.PtrToStringBSTR(bstr);
//处理字符串
}
finally
{
Marshal.ZeroFreeBSTR(bstr);
}
``` **BSTR/Unicode/ANSI有啥区别?** 我们看一下`Marshal`的方法列表就知道`Marshal`可以将`SecureString`转换成五种不同的字符串类型:`BSTR`,`CoTaskMemAnsi`,`CoTaskMemUnicode`, `GlobalAllocAnsi`, `GlobalAllocUnicode`。我当初有一个疑问就是这样子不同的类型转换有啥区别,我后来得出的结论是如果你只是想得到托管的`System.String`类型的话你选哪个作为中间变量都无所谓,只要用完释放资源就行了。 ###String --> SecureString的转换 `SecureString`不接受`String`去构造一个对象,我们有两种方式可以将`String`转成`SecureString`。 1. 通过AppendChar方法把`String`对象中的字符一个一个添加到`SecureString`后面。 2. 虽然`SecureString`不接受`String`来构造一个对象,但是它接受一个字符指针来构造一个对象。所以我们可以取的指向`String`对象的非托管`char*`指针来构造。 ```
string str = "zhengyi.me";
unsafe
{
fixed (char* p_str = str)
{
SecureString sstr = new SecureString(p_str, str.Length);
sstr.MakeReadOnly();
}
}
``` ##SecureString的基本操作 详情参考 [SecureString Class in MSDN](http://msdn.microsoft.com/en-us/library/system.security.securestring(v=vs.110).aspx) ##如何销毁一个String对象? 进一步思考一下,我们引入`SecureString`就是为了让敏感信息不在内存中裸奔。但是目前的.NET Framework提供的接口对`SecureString`的支持很有限,我们总会需要在某一小段时间内将其转换为`String`对象进行一些处理。那我们能不能让这些`String`对象*阅后即焚*呢? 在C++中我们如果要销毁一个字符串的话,无非就是把字符串所在的内存memset成0,然后将这块字符串的内存释放掉。但是在.NET中的话我们主要会遇到这么两个问题: - 众所周知,Java和.NET中的String类型是[不可变的](http://msdn.microsoft.com/zh-cn/library/362314fe.aspx)(immutable)。我们如何将其中的内容重置掉? - .NET中,String是一个[引用类型](http://msdn.microsoft.com/zh-cn/library/362314fe.aspx),所以String实例时会存在于堆上的。那么在一次GC以后如果进行了内存的压缩,那么String实例可能在内存上会被移动。所以也就不方面释放内存。 **如何破?** - 虽然说`String`在.NET中是不可变的,但是.NET中有一种unsafe的机制能够让我们像在C++中一样写*不安全代码*(使用指针的代码)。 - fixed关键字可以防止GC去在内存中挪动变量。 基本的代码就像下面这样: ```
unsafe {
//利用fixed关键字将字符串pin在内存上,确保其不会挪动而出现多个拷贝
fixed(char* c = str)
{
// 处理字符串
// 利用unsafe的代码遍历字符串将其内容重置
for(int i = 0; i < str.Length; i++)
{
c[i] = '\0';
}
}
}
``` ##总之
如同我在前篇文章中写的,我们所做的所有的这一切只是说提高了获取密码的难度和所需的时间。因为如果有人都能够拿到你的程序的内存的话,他可以干很多很多事情。 ##引用:
[1] 关于使用SecureString的一些介绍:http://blogs.msdn.com/b/fpintos/archive/2009/06/12/how-to-properly-convert-securestring-to-string.aspx [2] 还不错的关于SecureString的一些讨论: http://bytes.com/topic/c-sharp/answers/583441-destroy-string

继续SecureString的更多相关文章

  1. 编写高质量代码改善C#程序的157个建议——建议118:使用SecureString保存密钥等机密字符串

    建议118:使用SecureString保存密钥等机密字符串 托管代码中的字符串是一类特殊的对象,它们不可用被改变.每次使用System.String类张的方法之一时,或者使用此类型进行运算时(如赋值 ...

  2. (C#)System.Security.SecureString(表示应保密的文本)

    正常的String类型值,在脱离开作用域之后,其值在内存中并不会被立即销毁,这时如果有人恶意扫描你的内存,程序中所保存的机密信息就会暴露;于是就有了System.Security.SecureStri ...

  3. 17 安全字符串 System.Security.SecureString

  4. .NET基础拾遗(3)字符串、集合和流

    Index: (1)类型语法.内存管理和垃圾回收基础 (2)面向对象的实现和异常的处理 (3)字符串.集合与流 (4)委托.事件.反射与特性 (5)多线程开发基础 (6)ADO.NET与数据库开发基础 ...

  5. SharePoint 2016 配置向导报错 - The 'ListInternal' attribute is not allowed

    前言 配置SharePoint 2016的配置向导中,第三步创建配置数据库报错,然后百度.谷歌了一下,都没有解决,自己看日志搞定,也许会有人遇到类似问题,分享一下. 1.配置向导的错误截图,如下图: ...

  6. 探索c#之不可变数据类型

    阅读目录: 不可变对象 自定义不可变集合 Net提供的不可变集合 不可变优点 不可变对象缺点 不可变对象 不可变(immutable): 即对象一旦被创建初始化后,它们的值就不能被改变,之后的每次改变 ...

  7. System.Diagnostics.Process.Start的妙用

    我们经常会遇到在Winform或是WPF中点击链接或按钮打开某个指定的网址, 或者是需要打开电脑中某个指定的硬盘分区及文件夹, 甚至是"控制面板"相关的东西, 那么如何做呢? 答案 ...

  8. ADO.NET 中的新增功能

    ADO.NET 中的新增功能: .NET Framework (current version) 以下是 .NET Framework 4.5 中 ADO.NET 的新增功能. SqlClient D ...

  9. System.Diagnostics.Process 启动进程资源或调用外部的命令的使用

    经常看到一些程序在保存为一个txt,或者excel的文件的时候,保存完毕立即打开, 启动程序或打开文件的代码 System.Diagnostics.Process.Start(System.IO.Pa ...

随机推荐

  1. mysql解压缩安装(一)

    MySQL安装文件分为两种,一种是msi格式的,一种是zip格式的.如果是msi格式的可以直接点击安装,按照它给出的安装提示进行安装(相信大家的英文可以看懂英文提示),一般MySQL将会安装在C:\P ...

  2. java-base64编码和解码

    一.反射/*** * encode by Base64 */ public static String encodeBase64(byte[]input) throws Exception{ Clas ...

  3. html5新特性之画布

    1.canvas的理解 canvas是一个矩形区域,在这个区域内,通过js可以对区域内的每一帧像素控制 2.js操作canvas对象 canvas对象.getContext("2d" ...

  4. javascript 日期转换为中文

    function CNDateString(date) { var cn = ["〇","一","二","三",&quo ...

  5. HDU Game Theory

    5795 || 3032 把x个石子的堆分成非空两(i, j)或三堆(i, j, k)的操作->(sg[i] ^ sg[j])或(sg[i] ^ sg[j] ^ sg[k])是x的后继 #def ...

  6. oracle DBMS_LOCK.SLEEP()的使用

    create or replace procedure times isii positive:=1;beginloop dbms_lock.sleep(1);dbms_output.put_line ...

  7. mybatis多数据源配置

    项目目录如下: 按照顺序配置吧 首先是配置config jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/a ...

  8. 【分块打表】bzoj1662 [Usaco2006 Nov]Round Numbers 圆环数

    #include<cstdio> using namespace std; #define BN 380000 const int table[]={0,185815,378154,561 ...

  9. 文本框如果不输入任何内容提交过后是一个空字符串还是null

    1.在表单不填就提交的情况下,text类型和textarea类型的表单域,提交到服务端为空 2.checkbox.readio.select等表单域在为不填情况下不会提交到服务器,也就是说服务器接收不 ...

  10. 【整理】--【KERNEL】内核定时器

    一.LINUX内核定时器是内核用来控制在未来某个时间点(基于jiffies)调度执行某个函数的一种机制,其实现位于 <linux/timer.h> 和 kernel/timer.c 文件中 ...