Welcome

首页 / 软件开发 / C# / Effective C#原则47:选择安全的代码

Effective C#原则47:选择安全的代码2010-12-13 博客园 Wu.Country@侠缘译.Net运行时已经设计好了,一些怀有恶意的代码不能渗透到远程计算机上并 执行。目前一些分部式系统依懒于从远程机器上下载和执行代码。如果你可以通 过Internet或者以太网来发布你的软件,或者直接从web上运行,但你须要明白 CRL在你的程序集中的一些限制。如果CLR不是完全相信一个程序集,它会限制一 些的行为。这些调用代码要有访问安全认证(CAS)。从另一方面来说,CLR强制要 求基于角色的安全认证,这样这些代码才能或者不能在基于一个特殊的角色帐号 下运行。

安全违例是运行时条件,编译器不能强制它们。幸运的是,它 们绝不会在你的开发机器上出现,而且你所编译的代码从你自己的硬件上加载, 这就是说,它有更高的信任级别。讨论所有潜在的.Net安全模型可以足足写上几 本书,但你可以了解合理行为的一小部份,这样可以让你的程序集与.Net的安全 模式更容易的交互。这些推荐只有在你创建一个组件程序库时,或者是开发一些 通过网络发布的组件和程序集是才可以参考应用。

通过这个讨论,你应 该记住.Net是一个托管的环境。这个环境保证有一个明确的安全环境。在安装时 可以用.Net的配置策略来管理安全策略。大多数.Net框架库是在安装时对配置策 略是安全信任的。它会查明安全问题,这就是说CLR可以检测IL而且确保它不会 有什么潜在的危险行为,例如直接访问原始内存。它不会在访问本地资源时要求 特殊的安全权限进行断言。你应该试着遵守同样的检测,如果你的代码不须要任 何的安全权限,就应该避免使用CAS的API来对断定访问权限,否则你所做的只是 降低程序性能。

你要使用CAS的API来访问一些受保护的资源,而这些资 源是要求增加的特权的。很多通用的受保护资源是非托管的内存和文件系统。其 它一些受保护的资源还包括数据库,网络端口,windows注册表,以及打印子系 统。在每种情况下,如果调用代码没有足够的许可,试着访问这些资源都会引发 一个异常。而且,访问这些资源可能引发运行时建立一个安全栈上的询访,以确 保当前栈上的所有的程序集有恰当的许可。让我们看一下内存以及文件系统,讨 论安全系统和机密问题中最实际的一些问题。

不管什么时候,你都可以 通过创建恰当的安全程序集来避免非托管内存访问。一个安全的程序集,也就是 一个不用使用任何指针来访问其它非托管,或者托管的堆内存。不管你是否知道 ,你所创建的所有C#代码几乎都是安全的。除非你在C#编译器上打开了不安全的 编译开关/unsafe,否则你所创建的都是安全代码(译注:就算打开了开关也不是 说就编译成不安全代码了,还要看你的代码是怎样写的。)。/unsafe充许用户使 用CLR不进行的验证的指针。

要使用不安全代码的原因很少,特别是一常 规的任务中。指向原始内存的指针比要检测的安全的引用快一些。在一些经典的 数组中,它们可能要快上10倍以上。但当你使用不安全结构时,要明白任何的不 安全代码都会影响整个程序集。当你创建不安全块时,应该考虑把这些算法独立 到一个程序信中(参见原则32)。这样可以在整个程序上限制不安全代码的影响。 如果它是独立的,只有实际调用它的访问者才会受到影响。其它剩下的,你还是 可以在更严格的环境中使用安全机制。你可能还须要不安全代码来处理一些须要 直接指针的P/Invoke或者COM接口。同样的推荐:独立它。不安全代码只会影响 它自己的小程序集,不再有其它的。

对于访问的建议很简单:只要可能 ,都应该避免访问非托管内存。

接下来的安全核心就是文件系统。程序 要存储数据。从Internet上下载回来的代码,文件系统中的大多数地方都不能访 问,否则会有很大的安全漏洞。是的,完全不许访问文件系统就很难创建能使用 的程序。通过使用独立存储可以解决这一问题。独立存储可以穿越基于程序集而 独立的虚拟的目录,以及应用程序域,以及当前的用户。选择性的,你可以使用 更一般的独立存储虚拟目录,该目录是基于程序集或者当前用户的。

实 际上,受信任的程序集可以访问他们自己特殊的独立存储区域,但不能是文件系 统的其它地方。独立的存储目录是隐藏在其它程序集以及其它用户中的。你可以 使用System.IO.IsolatedStorage名字空间中的类来访问独立的存储。 IsolatedStorageFile类包含的方法可以很简单的访问System.IO.File类。实际 上,它是从 System.IO. FileStream 类派生下来的。写内容到独立存储的代码 几乎与写内容到任何文件里是一样的:

IsolatedStorageFile iso =
IsolatedStorageFile.GetUserStoreForDomain( );
IsolatedStorageFileStream myStream = new
IsolatedStorageFileStream( "SavedStuff.txt",
FileMode.Create, iso );
StreamWriter wr = new StreamWriter( myStream );
// several wr.Write statements elided
wr.Close ();