内容简介 Windows和基于Web的环境下的安全性一直都是人们关注的问题,特别是在破坏安全的活动日益猖獗的今天。而.NET安全性正是解决长期以来困扰计算机产业的安全问题的新方法,它与Win32安全性截然不同。本书主要讲述了.NET安全编程,同时引入了许多新的术语、概念及语法。内容涉及.NET体系结构、运行库安全策略、代码访问安全性、基于角色的安全、ASP.NET安全性、密码术,以及定制.NET安全性,本书还分别介绍了System.Security命名空间和System.Security.Permissions命名空间。本书适合在.NET平台下工作的专业开发人员。
前 言 Scott Stabbert(Microsoft的一位工程师)第一个向我介绍了.NET安全编程。Scott将.NET安全性描绘成与原来的Win32安全性完全不同。他用“完全不同”这个词直奔主题。听完他介绍了.NET安全性的复杂性后,我觉得仅用该词语来概括是远远不够的。. NET不使用安全属性,安全描述符,Discretionary Access Control List(自由访问控制列表),System Access Control List(系统访问控制列表),访问控制项,NTLM以及传统Win32安全性的其他功能。以前的安全模型已经完全被弃用。在Win32安全API上投入了相当多的精力后,这一转变使我怅然若失。 .NET安全性是解决长久困扰计算机产业的安全问题的一个新途径。Scott先生对.NET安全性的狂热也激发了我对.NET的兴趣。对.NET安全性作了单独的研究后,它同样给我留下了深刻印象。在这之后不久,我开始在Microsoft公司和其他公司教授.NET安全编程,从而也就自然而然地编写了这本关于.NET安全性的书。 .NET安全性的基本前提就是代码(而不是用户)才是安全策略的核心。这一简单而又根本的转变解决了长期以来的安全问题,如共享安全上下文和引诱攻击。我们每个人都曾经收到过一些值得怀疑的邮件——邮件发送者的姓名难以辨认,主题也是含混不清。更糟糕的是,这类邮件还带有附件。不过,对于这种附件把戏,任何一个有理智的人都不会打开来历不明的附件。然而,有时只是打开邮件就已经足以引发一次攻击了。正因为如此,您才会坐在那里反复考虑要不要打开那些可疑邮件。给嵌入的代码指派一个独立的安全上下文将使这一问题迎刃而解。而对于一些级别较低的代码,例如附件,最好授予有限的权限,防止引发安全攻击。现在,您可以打开邮件甚至附件,而不需要担心除垃圾邮件以外的任何可能产生的后果。 如何给程序集指派一个安全上下文呢?在Win32操作系统中,最为普遍的验证模式是Challenge/Response验证。Challenge就是一个已知用户的口令。信任机构根据challenge本地计算该口令,如果相同,用户就通过验证并被分配一个访问令牌,该令牌确定了该用户的安全上下文。Response是发送到请求机器的访问令牌。.NET对于代码采用一个类似的模型。公共语言运行库(CLR)询问程序集的证据而不是口令。CLR是一个信任机构。根据所提交的代表该程序集的证据,评估访问的信任级别并授予合适的权限。例如,下载缓存中运行的代码被部分信任并授予有限的权限。 尽管我们反对这么做,而实际上每个人仍然以管理员特权在本地机器上登录。 在本地计算机上运行的程序将会继承您的安全上下文。这是一个“共享安全”的上下文问题。您机器上的任何一个程序都为管理者权限所信任吗?回答是“不”。.NET访问独立于用户上下文的代码,并且根据应用程序(而不是用户)的特征指派一个信任级别和安全上下文。用户的安全上下文仍由操作系统强制。不过,.NET为代码增加了另一个安全层。因此可以说.NET安全性很完美。 0.1 托管语言 托管语言包括C#、Visual Basic.NET、Jsharp.NET、Jscript.NET等,而且这一队伍仍在扩大之中。在不久的将来,将会有Perl.NET、Fortran.NET和Ada.NET,并且可能会出现惊世的COBOL.NET。 本书使用C#作为托管语言,其实选择哪种语言并不重要。如果您是一位Visual Basic或Java编程人员,可以阅读Framework Class Library(FCL)中的.NET安全类,这在所有.NET语言中都是相同的。 看一下下列同一安全程序的C#和Visual Basic.NET版本。C#版本的程序如下所示: // C# Security Code using System; using System.Security; using System.Security.Permissions; class Starter { public static void Main() { FuncA(); StreamWriter s=new StreamWriter(@"c:\test.txt",true); s.WriteLine("Test"); s.Close(); } void FuncA() { FileIOPermission p = new FileIOPermission(FileIOPermissionAccess.Read, @"C:\test.txt"); p.PermitOnly(); } } 下面是该程序的Visual Basic.NET版本。 'VB Security Code imports System imports System.Security imports System.Security.Permissions imports System.IO public class Starter public shared sub Main() FuncA() dim s as new StreamWriter("c:\test.txt", true) s.WriteLine("VB Test") s.Close() end sub public shared sub FuncA() dim p as new _ FileIOPermission(FileIOPermissionAccess.Read, _ "C:\test.txt") p.PermitOnly() end sub end class 这些程序几乎是完全相同的。最大的区别在于C#是区分大小写的,并且要求每个语句的末尾都加分号。Microsoft公司的总经理及首席软件设计师Bill Gates将托管语言的选择称为生活方式的选择。而C#最适合我的生活方式。 本书的Visual Basic.NET示例代码均可在Web站点中找到。 本书中需要特别注意的安全问题将在安全警告和注意中作说明。 0.2 章节概述 本书的目的在于让专业开发人员全面认识安全编程。其中包括:代码访问安全性、基于角色的安全、密码术和定制.NET安全性。个别主题(如密码术和ASP.NET安全性)仅用一章的篇幅难以讲述清楚。因此,对于这些主题,我们只是希望读者对之能有一个基本的理解。 和任何一种新技术一样,.NET引入了大量的新术语、概念和语法。幸运的是, Michael Dunner(他也是微软公司的工程师)提供了很大的帮助。.NET安全性的语法并不十分困难,而新概念和术语的理解可能更具有挑战性。考虑到这个原因,我们将把重点放在.NET安全性的这些方面。 0.2.1 .NET体系结构 对.NET Framework有一个基本理解有助于学习.NET安全编程。第1章将探讨.NET体系结构、托管语言和公共语言运行库(CLR),并解释.NET的常用术语和概念。还会介绍Web Forms、ASP.NET、XML Web 服务、ADO.NET和.NET remoting。CLR是.NET的引擎。本章讲解了CLR的服务,例如实时编译(Just-in-Time Compilation)和无用单元收集(Garbage Collection)。本章最后介绍了一个基本的C#应用程序。 0.2.2 .NET 安全性的核心概念 本书的目标是为应用程序构建一个安全边界(perimeter)。第2章讨论了此边界中有关验证的一些小技巧。Manifest(清单) 和代码验证证实了程序集的正确性。然后回顾了应用程序域。应用程序域属于“轻量级”的进程,被提供和单独的进程相同的保护。强名程序集和共享的程序集比私有程序集更安全。强名程序集的优点会作详细讨论。从Internet和内部网下载的代码在下载缓存中执行并被授予有限的权限。第2章中还将讨论这个边界的其他更多内容。 0.2.3 运行库安全策略 运行库安全策略(Runtime Security Policy)相当于.NET 安全的路标。它把程序集映射到安全权限。CLR使用运行库安全策略确定程序集的信任级别,并在加载时将正确的权限授予程序集。在加载时授予程序集的权限是最多的。第3章讲述了运行库安全策略的组件:代码组、权限集、权限和证据。.NET提供Microsoft Framework Configuration 和Caspol 工具作为管理运行库安全策略的方法。第3章演示了这两种工具。 0.2.4 代码访问安全性 代码访问安全性强制了运行库安全策略。主要的命令是Demand,该命令执行堆栈遍历以便确认调用者已经请求了权限。请求一个与敏感资源相关的权限,从而保护对这一资源的访问。代码访问安全性也允许开发人员注释并改善运行库安全策略。开发人员可以命名可选的权限,指派最小的权限集,并且拒绝不需要的权限。第4章提供了对代码访问安全性的指导。 0.2.5 基于角色的安全 .NET并没有完全忘记用户。基于角色的安全服务于一般用户和Windows 用户。一般身份和负责者不是Windows 用户。相反地,Windows身份和负责者是已经经过身份验证的Windows 用户(用NTLM,NT Lem Manager)。Windows 负责者是访问令牌的包装器。角色是组,但不一定是Windows组。第5章将介绍如何分配一个执行安全上下文的线程,如何去模拟一个Windows用户,以及如何在企业应用程序中管理角色。 0.2.6 ASP.NET安全性 ASP.NET和Web Forms是.NET中必不可少的组成部分,即具有高度可用性、可从任何平台访问的、可部署到各种设备中的软件。当无线技术成为占优势的标准时,ASP.NET以优秀的桌面出现。由于特征是不相同的,因此保护Web应用程序与保护客户端应用程序的方式也有显著的区别。Web应用程序在公共“场所”运行,会受到无数的安全攻击。第6章阐述了ASP.NET应用程序独特的安全需求,包括窗体验证,URL授权和基于角色的安全等。 0.2.7 密码术 密码术是关于保密和证明身份的。在深入具体内容之前必须理解密码术的结构。第7章首先介绍了重要的密码术概念和术语,说明了加密、解密、散列和数字签名。该章首先用大量示例代码讲述了Crypto API,最后详细讨论了.NET中的密码术,特别介绍了CryptoStream类。 0.2.8 定制.NET安全性 Microsoft使.NET具备可扩展性。新的攻击持续不断地出现,同时也会出现抵御这些攻击的算法。在安全性这一领域,任何事物都不是静止的。另外,每个应用程序都是惟一的,有着各自独特的需求。Microsoft不可能预见安全需求的每一次转变。解决的方法是使.NET安全性具备可扩展性。第8章将处理在运行库安全策略中出现的定制目标。在.NET中可以很容易地定制权限、权限集、代码组和证据。 0.2.9 System.Security命名空间 System.Security命名空间包含了.NET安全性的基础结构的大部分内容。了解该命名空间的知识是了解.NET安全性的第一步。第9章介绍了该命名空间的类并且提供了示例代码。 0.2.10 System.Security.Permissions命名空间 System.Security.Permissions命名空间包括很多运行库安全策略和代码访问安全性所使用的类。第10章介绍了这些类并且对运行库安全策略、代码访问安全性和定制.NET 安全在这章中作了补充说明。