继续SecureString
上回写了关于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的更多相关文章
- 编写高质量代码改善C#程序的157个建议——建议118:使用SecureString保存密钥等机密字符串
建议118:使用SecureString保存密钥等机密字符串 托管代码中的字符串是一类特殊的对象,它们不可用被改变.每次使用System.String类张的方法之一时,或者使用此类型进行运算时(如赋值 ...
- (C#)System.Security.SecureString(表示应保密的文本)
正常的String类型值,在脱离开作用域之后,其值在内存中并不会被立即销毁,这时如果有人恶意扫描你的内存,程序中所保存的机密信息就会暴露;于是就有了System.Security.SecureStri ...
- 17 安全字符串 System.Security.SecureString
- .NET基础拾遗(3)字符串、集合和流
Index: (1)类型语法.内存管理和垃圾回收基础 (2)面向对象的实现和异常的处理 (3)字符串.集合与流 (4)委托.事件.反射与特性 (5)多线程开发基础 (6)ADO.NET与数据库开发基础 ...
- SharePoint 2016 配置向导报错 - The 'ListInternal' attribute is not allowed
前言 配置SharePoint 2016的配置向导中,第三步创建配置数据库报错,然后百度.谷歌了一下,都没有解决,自己看日志搞定,也许会有人遇到类似问题,分享一下. 1.配置向导的错误截图,如下图: ...
- 探索c#之不可变数据类型
阅读目录: 不可变对象 自定义不可变集合 Net提供的不可变集合 不可变优点 不可变对象缺点 不可变对象 不可变(immutable): 即对象一旦被创建初始化后,它们的值就不能被改变,之后的每次改变 ...
- System.Diagnostics.Process.Start的妙用
我们经常会遇到在Winform或是WPF中点击链接或按钮打开某个指定的网址, 或者是需要打开电脑中某个指定的硬盘分区及文件夹, 甚至是"控制面板"相关的东西, 那么如何做呢? 答案 ...
- ADO.NET 中的新增功能
ADO.NET 中的新增功能: .NET Framework (current version) 以下是 .NET Framework 4.5 中 ADO.NET 的新增功能. SqlClient D ...
- System.Diagnostics.Process 启动进程资源或调用外部的命令的使用
经常看到一些程序在保存为一个txt,或者excel的文件的时候,保存完毕立即打开, 启动程序或打开文件的代码 System.Diagnostics.Process.Start(System.IO.Pa ...
随机推荐
- 大前端学习笔记整理【七】HTTP协议以及http与https的区别
前言 还是老样子,新博客开始前总是想先啰嗦几句...HTTP协议其实在当初学习java时老师就有提过...但是...反正就那么过去了... 这段时间公司的项目正好要求做https的转换和迁移,然后自己 ...
- SQl server 关于重复插入数据的测试
最近发布的脚本,有那种防止重复插入数据(包括存在时更新,不存在是插入的处理,判断的方向可能与下面的示例相反) 使用类似下面的 SQL declare @id int, @value int if no ...
- Eclipse在线集成maven M2eclipse插件
首先说下版本: Eclipse:3.6 Maven:3.3.1,若不知道如何在本地安装Maven,请参见我的另一篇文章:Window下安装Maven 废话少说,直接讲步骤就好: 1.打开eclipse ...
- iOS开发中的各种错误
提交iTunesconnect遇到的问题: 1. error itms-90179 Invalid Code Signing. 解决:发现是发布正式被撤销了,重新生成发布Certificates,重新 ...
- SVN的服务器端用户权限配置
第一:用户的配置 SVN和apache整合的话,用户可以直接使用htpasswd dav_svn.passwd_file_address USERNAME来配置. 而账户的管理可以用dav_svn.a ...
- UI Automation Test
UI Automation test is based on the windows API. U can find the UI Automation MSDN file from http://m ...
- mysql数据表操作&库操作
首先登陆mysql:mysql -uroot -proot -P3306 -h127.0.0.1 查看所有的库:show databases; 进入一个库:use database; 显示所在的库:s ...
- Redis多机常用架构-sentinel
哨兵经典架构 sentinel结构 哨兵工作原理 Sentinel 通过配置文件发现Master,如下: Sentinel 通过向Master发送 INFO 命令来自动获得所有Slave的地址 跟Ma ...
- 解决Get请求的长度限制
错误提示: HTTP Error 404.15 - Not Found The request filtering module is configured to deny a request whe ...
- Java开发Webservice的组件
参考:http://bbs.csdn.net/topics/390900831 转自:http://blog.csdn.net/dragoo1/article/details/50759222 htt ...